تُستخدَم أنواع البيانات في لغة جو للإشارة إلى نوع معيَّن من البيانات وتحديد القيم التي يمكنك إسنادها لذلك النوع والعمليات التي يمكنك إجراؤها عليها، فهناك أوقات نحتاج إلى تحويل القيم من نوع إلى آخر لمعالجتها بطريقة مختلفة، فقد نحتاج مثلًا إلى وصل القيم العددية بالسلاسل النصية أو إظهار الفواصل العشرية لأعداد صحيحة، وغالبًا ما تُعامَل البيانات التي يُدخلها المستخدِم في جو على أنها سلاسل نصية، حتى إذا تضمنت أعدادًا، وبالتالي يتوجب عليك تحويلها إلى بيانات عددية إذا أردت إدخالها في عمليات حسابية.
تُعَدّ جو لغةً ثابتةً تتطّلب تحديد النوع statically typed language، لذا تكون أنواع البيانات مرتبطةً بالمتغيرات وليس بالقيم، أي في حال كان لديك متغير من النوع int
، فلا يمكن أن يُسنَد إليه متغير من نوع آخر، وسيرشدك هذا المقال إلى كيفية تحويل الأعداد والسلاسل النصية، بالإضافة إلى تقديم بعض الأمثلة التوضيحية.
تحويل الأنواع العددية
هناك نوعان رئيسيان من البيانات العددية في جو وهما الأعداد الصحيحة والأعداد العشرية. ستعمل في بعض الأحيان على شيفرة برمجية كتبها شخص آخر، وقد تحتاج إلى تحويل عدد صحيح إلى عدد عشري أو العكس، أو قد تجد أنك تستخدم عددًا صحيحًا في الوقت الذي تحتاج إلى أعداد عشرية، لذلك تتوفر في جو توابع مضمّنة تُسهِّل عليك التحويل بين الأنواع العددية.
التحويل بين أنواع الأعداد الصحيحة
تتضمن جو العديد من أنواع البيانات الصحيحة التي يمكنك التبديل بينها حسب الحاجة ومتطلبات الأداء أو لأسباب أخرى، فيُنشئ جو في بعض الأحيان مثلًا قيمًا عدديةً من النوع int
تلقائيًا، وبالتالي في حال أدخلت أعدادًا من النوع int64
، فلن تتمكن استخدام العدد السابق الذي ولدته جو مع العدد الذي أدخلته ضمن تعبير رياضي واحد لأنهما من نوعين مختلفين.
افترض أنه لديك متغير من النوع int8
وتحتاج إلى تحويله إلى int32
، فيمكنك إجراء ذلك عن طريق استخدام الدالة int32()
:
var index int8 = 15 var bigIndex int32 bigIndex = int32(index) fmt.Println(bigIndex)
يكون الخرج كما يلي:
15
عرّفنا متغير index
من النوع int8
ومتغير bigIndex
من النوع int32
ثم حوّلنا نوع المتغير index
إلى النوع int32
وخزّنا النتيجة في المتغير bigIndex
ثم طبعنا قيمته، وللتأكد من عملية التحويل أو لتفقّد نوع البيانات لأحد المتغيرات، استخدم العنصر النائب T%
مع دالة الطباعة fmt.Printf
كما يلي:
fmt.Printf("index data type: %T\n", index) fmt.Printf("bigIndex data type: %T\n", bigIndex)
يكون الخرج كما يلي:
index data type: int8 bigIndex data type: int32
لاحظ أنه يطبع نوع البيانات للمتغير وليس قيمته.
يمكنك أيضًا التحويل من نوع بيانات كبير إلى نوع أصغر مثل تحويل من int64
إلى int8
كما يلي:
var big int64 = 64 var little int8 little = int8(big) fmt.Println(little)
يكون الخرج كما يلي:
64
لكن انتبه إلى أنه عند التحويل من نوع أكبر إلى نوع أصغر قد تتجاوز القيمة الأكبر بالقيمة المطلقة التي يمكن لهذا النوع تخزينها، ففي حال تجاوزت القيمة تلك، فستحدث عملية التفاف wraparound كما في المثال التالي:
var big int64 = 129 var little = int8(big) fmt.Println(little)
يكون الخرج كما يلي:
-127
أكبر قيمة يمكن أن يخزنها متغير من النوع int8
هي 127 وأصغر قيمة -127، فإذا تجاوزتها، فسيحدث التفاف، وبما أنّ 129 في المثال السابق أكبر من القيمة العظمى التي يمكن للنوع المحدد تخزينه، فقد حدث التفاف إلى القيمة الأصغر، أي حوّله إلى أصغر قيمة ممكنة فيه.
تحويل الأعداد الصحيحة إلى أعداد عشرية
الأمر مشابه لعمليات التحويل التي أجريناها منذ قليل، إذ سنستخدِم هنا الدالة float64()
أو float32()
لإجراء عمليات التحويل:
var x int64 = 57 var y float64 = float64(x) fmt.Printf("%.2f\n", y)
يكون الخرج كما يلي:
57.00
لاحظ أننا حوّلنا نوع المتغير x
ذو القيمة الابتدائية 57
من int64
إلى float64
، وبالتالي أصبحت57.00
، أخيرًا استخدمنا العنصر النائب %.2f
ضمن دالة الطباعة للإشارة إلى عدد عشري مع الإبقاء على رقمين بعد الفاصلة.
وبذلك يمكنك استخدام float32()
أو float64()
لتحويل الأعداد العشرية إلى أعداد صحيحة.
تحويل الأعداد العشرية إلى أعداد صحيحة
يمكنك تحويل الأعداد العشرية إلى أعداد صحيحة باستخدام الدوال نفسها التي استخدمناها سابقًا عند التحويل بين أنواع الأعداد الصحيحة، ولكن انتبه إلى أنّ تغير النوع من عشري إلى صحيح سيفقدك الأعداد الموجودة بعد الفاصلة (الأجزاء العشرية أي الأرقام التي بعد الفاصلة العشرية)، وبالتالي قد تؤثر على دقة الحالة أو العملية كما في المثال التالي:
var f float64 = 390.8 var i int = int(f) fmt.Printf("f = %.2f\n", f) fmt.Printf("i = %d\n", i)
يكون الخرج كما يلي:
f = 390.80 i = 390
عرّفنا في المثال السابق متغير f
من النوع العشري وهيأناه بقيمة 390.8
ثم عرّفنا متغير i
من النوع الصحيح وهيّأناه بقيمة المتغيّر f
بعد تحويّله إلى النوع الصحيح من خلال الدالة int
ثم طبعنا قيمتهما، ولاحظ أنه عندما حوّلنا القيمة 390.8
إلى 390
، أُسقطت القيمة الموجودة بعد الفاصلة، وتجدر الملاحظة إلى أنّ جو لا تُقرِّب العدد؛ وإنما تهمل كل الأعداد بعد الفاصلة فقط.
ولنأخذ المثال التالي الذي يُعرِّف المتغير b
ويعطيه القيمة 125.0
والمتغير c
مع القيمة 390.8
ثم يطبعهما على شكل عدد صحيح:
b := 125.0 c := 390.8 fmt.Println(int(b)) fmt.Println(int(c))
يكون الخرج كما يلي:
125 390
عند تحويل عدد عشري إلى عدد صحيح باستعمال int()
، تقتص لغة Go الأعداد العشرية وتبقي على العدد الصحيح فقط، وانتبه أننا قلنا "تقتص" أي أنها تزيل الفواصل العشرية دون إجراء عملية تقريب، فلن يُقرَّب العدد 390.8
إلى 391
بل سيصبح بعد التحويل 390
.
تحويل الأعداد عبر القسمة
تُسقط جو الفواصل إذا وُجِدت أيضًا عند تقسيم على آخر صحيح:
a := 5 / 2 fmt.Println(a)
يكون الخرج كما يلي:
2
إذا كان أحد الأعداد في عملية القسمة من النوع العشري float، فستُعَدّ كل الأعداد عشريةً وكذلك الناتج كما يلي:
a := 5.0 / 2 fmt.Println(a)
يكون الخرج كما يلي:
2.5
كما تلاحظ لم تُسقَط الأعداد بعد الفاصلة هذه المرة.
تحويلات السلاسل النصية
تُعَدّ السلسلة النصية تسلسلًا مؤلفًا من محرف واحد أو أكثر، ويمكن أن يكون المحرف حرفًا أبجديًا أو عددًا أو رمزًا، وتُعَدّ السلاسل النصية إحدى الأشكال الشائعة من البيانات في عالم البرمجة، وقد نحتاج إلى تحويل السلاسل النصية إلى أعداد أو أعداد إلى سلاسل نصية في كثير من الأحيان خاصةً عندما نعمل على البيانات التي ينشئها المستخدِمون.
تحويل الأعداد إلى سلاسل نصية
يمكن إنجاز ذلك من خلال استخدام التابع strconv.Itoa
من إحدى حزم لغة جو القياسية strconv
في حزمة جو القياسية. وذلك بتمرير العدد الصحيح أو العشري إلى هذا التابع والذي سيتكفل بإجراء عملية التحويل إلى سلسلة نصية، إذ سنحوّل العدد الصحيح 12 إلى سلسلة نصية في المثال التالي:
package main import ( "fmt" "strconv" ) func main() { a := strconv.Itoa(12) fmt.Printf("%q\n", a) }
عرّفنا متغير a
يُمثّل سلسلة نصية وأسندنا إليه القيمة المُعادة من الدالة strconv.Itoa
والتي ستعبّر عن العدد 12 بوصفه سلسلةً نصيةً، ثم استخدمنا دالة الطباعة لإظهار نتيجة التحويل، كما أننا استخدمنا معها العنصر النائب q%
لإظهار السلسلة النصية مع علامتي الاقتباس ويكون الخرج كما يلي:
"12"
تشير علامات الاقتباس حول العدد 12 إلى أنّ العدد الصحيح قد أصبح سلسلةً نصيةً.
يمكنك البدء في معرفة مدى إمكانية تحويل الأعداد الصحيحة إلى سلاسل من خلال المتغيرات، ولنفترض أنك تريد تتبع التقدم اليومي في البرمجة للمستخدِم وتريد إدخال عدد سطور التعليمات البرمجية التي يكتبها في كل مرة، كما تريد عرض هذه الملاحظات للمستخدِم مع طباعة قيم السلسلة والأعداد الصحيحة في الوقت نفسه:
package main import ( "fmt" ) func main() { user := "Sammy" lines := 50 fmt.Println("Congratulations, " + user + "! You just wrote " + lines + " lines of code.") }
سيعطي الخرج الخطأ التالي:
invalid operation: ("Congratulations, " + user + "! You just wrote ") +lines (mismatched types string and int)
لا يمكنك وصل السلاسل النصية مع الأعداد الصحيحة في جو، لذلك يجب عليك تحويل المتغير lines
إلى سلسلة:
package main import ( "fmt" "strconv" ) func main() { user := "Sammy" lines := 50 fmt.Println("Congratulations, " + user + "! You just wrote " + strconv.Itoa(lines) + " lines of code.”) }
يكون الخرج كما يلي:
Congratulations, Sammy! You just wrote 50 lines of code.
إذا أردت تحويل عدد عشري إلى سلسلة، فالأمر مشابه لما سبق. استخدم التابع fmt.Sprint
من الحزمة fmt
من مكتبة جو القياسية، إذ يعيد هذا التابع السلسلة النصية المكافئة للعدد العشري الذي مررته له:
package main import ( "fmt" ) func main() { fmt.Println(fmt.Sprint(421.034)) f := 5524.53 fmt.Println(fmt.Sprint(f)) }
يكون الخرج كما يلي:
421.034 5524.53
يمكنك إجراء تجربة وصل عدد حقيقي مع سلسلة نصية بعد تحويله إلى سلسلة كما يلي:
package main import ( "fmt" ) func main() { f := 5524.53 fmt.Println("Sammy has " + fmt.Sprint(f) + " points.") }
يكون الخرج كما يلي:
Sammy has 5524.53 points.
نجحت عملية التحويل بالفعل والدليل على ذلك أن عملية الوصل نجحت.
تحويل السلاسل إلى أعداد
يمكن استخدام الحزمة strconv
من مكتبة جو القياسية لإنجاز عملية التحويل من سلاسل نصية إلى أعداد صحيحة وعشرية، إذ تحتاج لهكذا عملية تحويل كثيرًا لا سيما عندما تحتاج إلى إدخال البيانات من المستخدِم، فقد تحتاج مثلًا إلى أن يُدخل المستخدِم عمره والذي تُعده جو سلسلةً وليس عددًا، لذا أنت بحاجة إلى تحويله إلى عدد صحيح، فإذا كان العدد المدخل صحيحًا، فاستخدم الدالة strconv.Atoi
؛ أما إذا كان عشريًا، فاستخدم الدالة strconv.ParseFloat
.
سنكمل الآن مع المثال السابق نفسه الذي تحدثنا فيه عن المستخدِم الذي يتتبع سطور التعليمات البرمجية المكتوبة كل يوم، فإذا أردت معالجة تلك القيم رياضيًا لتقديم ملاحظات أكثر تشويقًا للمستخدِم، فستحتاج لتحويلها إلى أعداد أولًا:
package main import ( "fmt" ) func main() { lines_yesterday := "50" lines_today := "108" lines_more := lines_today - lines_yesterday fmt.Println(lines_more) }
سيتولد الخطأ التالي عند تنفيذ الشيفرة السابقة:
invalid operation: lines_today - lines_yesterday (operator - not defined on string)
المتغيران اللذان تحاول طرحهما مُمثلان على أساس سلاسل نصية، لذا لا يمكن إجراء حسابات عليهما، وبالتالي سنصلح المشكلة من خلال استخدام التابع strconv.Atoi()
لتحويل قيم المتغيرات إلى أعداد صحيحة:
package main import ( "fmt" "log" "strconv" ) func main() { lines_yesterday := "50" lines_today := "108" yesterday, err := strconv.Atoi(lines_yesterday) if err != nil { log.Fatal(err) } today, err := strconv.Atoi(lines_today) if err != nil { log.Fatal(err) } lines_more := today - yesterday fmt.Println(lines_more) }
استخدمنا if
لتجنب توقف البرنامج بسبب حدوث خطأ غير متوقع مثل أن تكون السلسلة التي نرغب بتحويلها ليست عددًا صحيحًا أساسًا أو أنها سلسلة فارغة، ويدلنا على حدوث مثل هذه الأخطاء الدالة strconv.Atoi
من خلال إعادة القيمة nil
في حال كانت السلسلة الممررة غير ملائمة لعملية التحويل، وبالتالي في حال حدوث خطأ سندخل إلى تعليمة if
ثم سنسجّل الخطأ من خلال log.Fatal
ونخرج من البرنامج.
يكون الخرج كما يلي:
58
إذا حاولت تحويل سلسلة لا تمثّل عددًا صحيحًا:
package main import ( "fmt" "strconv" ) func main() { a := "not a number" b, err := strconv.Atoi(a) fmt.Println(b) fmt.Println(err) }
فستحصل على الخطأ التالي:
0 strconv.Atoi: parsing "not a number": invalid syntax
لم تُسنَد قيمة إلى المتغير b
نظرًا لفشل الدالة strconv.Atoi
في إجراء التحويل على الرغم من أنه قد صُرِّح عن b
، ولاحظ أنّ قيمة b
تساوي 0
، وذلك لأنّ جو لديها قيم افتراضية يُشار إليها بالقيم الصفرية في جو، كما توفر strconv.Atoi
خطأً يصف سبب فشل تحويل السلسلة النصية أيضًا.
التحويل بين السلاسل والبايتات
تُخزّن السلاسل النصية في جو على هيئة شريحة من البايتات، ويمكنك التحويل من سلسلة إلى شريحة من البايت أو العكس من خلال الدوال ()byte[]
و ()string
:
package main import ( "fmt" ) func main() { a := "my string" b := []byte(a) c := string(b) fmt.Println(a) fmt.Println(b) fmt.Println(c) }
خزّنتَ هنا سلسلةً في المتغير a
ثم حوّلتها إلى شريحة من البايتات b
ثم حوّلتها إلى سلسلة c
من جديد، وبعد ذلك طبعتَ a
و b
و c
على الشاشة، ويكون الخرج كما يلي:
my string [109 121 32 115 116 114 105 110 103] my string
يمثِّل السطر الأول السلسلة النصية الأصلية ويمثِّل السطر الثاني السلسلة النصية بعد تحويلها إلى شريحة من البايتات؛ أما السطر الثالث، فيُظهر أمان عملية التحويل من وإلى شريحة بايتات.
الخاتمة
وضحنا في هذا المقال كيفية تحويل العديد من أنواع البيانات الأصلية المهمة إلى أنواع بيانات أخرى باستخدام التوابع المُضمّنة، إذ يوفِّر لك تحويل أنواع البيانات في جو مرونةً إضافيةً في مشاريعك البرمجية.
ترجمة -وبتصرف- للمقال How To Convert Data Types inGo لصاحبه Gopher Guides.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.