اذهب إلى المحتوى

تحويل أنواع البيانات في لغة جو Go


هدى جبور

تُستخدَم أنواع البيانات في لغة جو للإشارة إلى نوع معيَّن من البيانات وتحديد القيم التي يمكنك إسنادها لذلك النوع والعمليات التي يمكنك إجراؤها عليها، فهناك أوقات نحتاج إلى تحويل القيم من نوع إلى آخر لمعالجتها بطريقة مختلفة، فقد نحتاج مثلًا إلى وصل القيم العددية بالسلاسل النصية أو إظهار الفواصل العشرية لأعداد صحيحة، وغالبًا ما تُعامَل البيانات التي يُدخلها المستخدِم في جو على أنها سلاسل نصية، حتى إذا تضمنت أعدادًا، وبالتالي يتوجب عليك تحويلها إلى بيانات عددية إذا أردت إدخالها في عمليات حسابية.

تُعَدّ جو لغةً ثابتةً تتطّلب تحديد النوع 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.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...