1 مقدمة إلى أنواع البيانات في لغة Go

في لغة Go، تعتبر أنواع البيانات أساس البرمجة، حيث تحدد شكل البيانات التي يمكن للمتغيرات تخزينها. يتم تقسيم أنواع البيانات الأساسية التي تقدمها لغة Go بشكل رئيسي إلى الفئات التالية:

نوع البيانات الوصف استخدام الذاكرة
bool نوع بولياني، يُستخدم لتخزين قيم صح أو خطأ 1 بايت
int، uint أعداد صحيحة موقعة وغير موقعة، الحجم الافتراضي يعتمد على منصة النظام 4 أو 8 بايت
int8, uint8 أعداد صحيحة موقعة وغير موقعة ب 8 بت 1 بايت
int16, uint16 أعداد صحيحة موقعة وغير موقعة ب 16 بت 2 بايت
int32, uint32 أعداد صحيحة موقعة وغير موقعة ب 32 بت 4 بايت
int64, uint64 أعداد صحيحة موقعة وغير موقعة ب 64 بت 8 بايت
float32 عدد عائم ب 32 بت 4 بايت
float64 عدد عائم ب 64 بت 8 بايت
complex64 عدد مركب مع أجزاء حقيقية ووهمية ب 32 بت 8 بايت
complex128 عدد مركب مع أجزاء حقيقية ووهمية ب 64 بت 16 بايت
byte مشابه ل uint8 1 بايت
rune مشابه ل int32، يمثل نقطة رمز يونيكود 4 بايت
string نوع السلسلة يعتمد على طول السلسلة
error واجهة الخطأ، تُستخدم لإرجاع معلومات الخطأ لا يوجد حجم ثابت

يمكن اختيار هذه الأنواع وفقًا للاحتياجات المختلفة، مثل الحسابات العددية، معالجة النصوص، أو التحكم المنطقي.

2 أنواع بيانات الأعداد الصحيحة

2.1 نظرة عامة على أنواع الأعداد الصحيحة

تحتوي لغة Go على العديد من أنواع الأعداد الصحيحة المدمجة، مصنّفة على النحو التالي:

  • أعداد صحيحة موقعة: int8، int16، int32 (أو runeint64، وint
  • أعداد صحيحة غير موقعة: uint8 (أو byteuint16، uint32، uint64، وuint

حيث يكون حجم int و uint هو 4 بايت على أنظمة 32 بت و 8 بايت على أنظمة 64 بت. تُظهر الجدول أدناه نطاقات القيم لأنواع بيانات الأعداد الصحيحة:

النوع نطاق القيم
int8 -128 إلى 127
uint8 0 إلى 255
int16 -32768 إلى 32767
uint16 0 إلى 65535
int32 -2147483648 إلى 2147483647
uint32 0 إلى 4294967295
int64 -9223372036854775808 إلى 9223372036854775807
uint64 0 إلى 18446744073709551615

2.2 استخدام متغيرات الأعداد الصحيحة

يكون الصيغة الأساسية لتعريف متغير عدد صحيح كما يلي:

var اسم_المتغير نوع_البيانات = القيمة_الأولية

على سبيل المثال:

package main
import "fmt"

func main() {
    var a int = 10 // متغير عدد صحيح موقع
    var b uint = 20 // متغير عدد صحيح غير موقع
    var c int8 = -128 // أصغر قيمة int8
    fmt.Println(a, b, c)
}

2.3 عمليات الأعداد الصحيحة

تدعم لغة Go العمليات الحسابية الشائعة، مثل الجمع (+)، الطرح (-)، الضرب (*)، القسمة (/)، والباقي (%)، بالإضافة إلى العوامل البتية مثل العمليات البتية "و" (&)، "أو" (|)، "أكس أو" (^)، التحويل البتي لليمين (<<)، والتحويل البتي لليسار (>>).

package main
import "fmt"

func main() {
    x := 10
    y := 3

    // العمليات الحسابية
    fmt.Println(x + y) // الجمع
    fmt.Println(x - y) // الطرح
    fmt.Println(x * y) // الضرب
    fmt.Println(x / y) // القسمة
    fmt.Println(x % y) // الباقي

    // عمليات البت
    fmt.Println(x & y)  // العملية البتية "و"
    fmt.Println(x | y)  // العملية البتية "أو"
    fmt.Println(x ^ y)  // العملية البتية "أكس أو"
    fmt.Println(x << 1) // تحويل بتي لليسار بمقدار 1
    fmt.Println(x >> 1) // تحويل بتي لليمين بمقدار 1
}

3 أنواع بيانات الأعداد العائمة

3.1 نظرة عامة على أنواع البيانات العائمة

في لغة Go ، تشمل أنواع الأعداد العائمة float32 و float64 ، والتي تعتبر تمثيلًا للبيانات العائمة بتنسيق 32 بت و 64 بت. بشكل عام ، يُوصى باستخدام float64 لأنه يوفر نطاقًا أوسع ودقة أكبر.

  • يحتوي float32 على حوالي 23 بت مهمة ، مما يوفر حوالي 7 أرقام عشرية من الدقة.
  • يحتوي float64 على حوالي 52 بت مهمة ، مما يوفر حوالي 16 رقمًا عشريًا من الدقة.

3.2 استخدام المتغيرات العائمة

يمكن تعريف المتغيرات العائمة عن طريق توفير القيم الأساسية مباشرة أو باستخدام كلمة المفتاح var:

package main
import "fmt"

func main() {
    var f1 float32 = 3.14 // تحديد نوع float32 بشكل صريح
    f2 := 3.14            // تم افتراضه تلقائيًا كنوع float64
    fmt.Println(f1, f2)
}

3.3 العمليات الحسابية للأعداد العائمة والمشكلات

قد تؤدي عمليات الحساب للأعداد العائمة إلى فقدان الدقة. أداء العمليات بدقة عالية هو مشكلة شائعة ، خاصةً عند طرح رقمين قريبين جدًا.

package main
import "fmt"

func main() {
    f1 := .1
    f2 := .2
    f3 := f1 + f2
    fmt.Println(f3) // قد لا يكون الإخراج المتوقع هو .3 بسبب مشكلات الدقة

    // إصلاح مشكلات الدقة باستخدام الإخراج المهيأ
    fmt.Printf("%.1f\n", f3) // الإخراج المصحح إلى .3
}

4 نوع بيانات البوليان

4.1 نظرة عامة على نوع البيانات البولياني

البوليان هو أبسط نوع بيانات ، ويمكن أن يأخذ فقط قيمتين: true (صحيح) و false (خاطئ). إنه يحتل مكانة مهمة جدًا في التعبيرات الشرطية وهياكل التحكم في الحلقات.

4.2 استخدام المتغيرات البوليانية

تعريف واستخدام المتغيرات البوليانية:

package main
import "fmt"

func main() {
    var success bool = true
    var fail bool = false
    fmt.Println("Operation successful:", success)
    fmt.Println("Operation failed:", fail)
}

غالبًا ما يتم استخدام القيم البوليانية في التعبيرات الشرطية:

package main
import "fmt"

func main() {
    a := 10
    b := 20
    fmt.Println("a == b:", a == b) // false
    fmt.Println("a < b:", a < b)   // true
}

5 نوع بيانات السلسلة

5.1 نظرة عامة على السلاسل

السلسلة هي مجموعة من الأحرف. في لغة Go ، السلاسل غير قابلة للتغيير. تتكون كل سلسلة من جزءين: مؤشر إلى صفيف البايتات الأساسي وطول. يمكن أن تحتوي السلاسل على أي بيانات بما في ذلك البايتات.

5.2 استخدام المتغيرات السلسلة

غالبًا ما يتم تعريف المتغيرات السلسلة باستخدام علامات اقتباس مزدوجة " للإنشاء ، ولكن يمكنك أيضًا استخدام علامات اقتباس عكسية ` لإنشاء سلاسل على عدة أسطر:

package main
import "fmt"

func main() {
    var s1 string = "hello"
    s2 := "world"
    s3 := `This is a 
    multiple line 
    string`
    fmt.Println(s1)
    fmt.Println(s2)
    fmt.Println(s3)
}

بمجرد إنشاء سلسلة ، لا يمكن تغيير محتواها. العملية التالية غير قانونية وستؤدي إلى خطأ في الترجمة:

s := "hello"
s[] = 'H` // خطأ في الترجمة: المحتوى الخاص بالسلسلة لا يمكن تغييره

5.3 العمليات على السلاسل

السلاسل شائعة ومهمة جدًا في البرمجة. توفر لغة Go مجموعة غنية من الدوال المدمجة للتلاعب بالسلاسل. فيما يلي بعض العمليات المستخدمة بشكل شائع.

5.3.1 اقتران السلاسل

في لغة Go ، يمكنك استخدام عامل الجمع (+) لاقتران السلاسل ، وهو الطريقة الأكثر مباشرة. بالإضافة إلى ذلك ، عند التعامل مع اقتران متكرر لعدة سلاسل ، من المُوصَى باستخدام strings.Builder للحصول على أداءٍ أفضل.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // اقتران السلاسل باستخدام الإضافة
    hello := "Hello, "
    world := "World!"
    result := hello + world
    fmt.Println(result) // الإخراج: Hello, World!

    // اقتران السلاسل باستخدام strings.Builder
    var sb strings.Builder
    sb.WriteString("Hello, ")
    sb.WriteString("World!")
    fmt.Println(sb.String()) // الإخراج: Hello, World!
}

5.3.2 تقسيم السلاسل النصية

يمكن تقسيم السلاسل النصية باستخدام دالة strings.Split، الّتي تقسم النص إلى قطع بناءً على الفاصل المحدد.

package main

import (
    "fmt"
    "strings"
)

func main() {
    // تعريف نص
    sentence := "Go هي لغة برمجة مفتوحة المصدر"

    // تقسيم النص بواسطة المسافة
    words := strings.Split(sentence, " ")
    for _, word := range words {
        fmt.Printf("%s\n", word)
    }
    // الناتج:
    // Go
    // هي
    // لغة
    // برمجة
    // مفتوحة
    // المصدر
}

5.3.3 الوصول بالفهرس

في Go، السلسلة النصية هي تسلسل لا يمكن تغييره من البايتات. يمكنك استخدام الفهرسة للوصول إلى بايتات محددة في سلسلة. ومع ذلك، من المهم ملاحظة أنه نظرًا لأن السلسلة قد تحتوي على أحرف متعددة البايتات (مثل الأحرف المشفرة بترميز UTF-8)، فإن الفهرسة المباشرة قد لا تعيد الحرف الواحد المتوقع.

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    for i := 0; i < len(s); i++ {
        fmt.Printf("%d: %x\n", i, s[i])
    }
    // ملاحظة: سيتم طباعة التمثيل الست عشري للبايتات، وليس الأحرف
}

للتكرار عبر السلسلة حسب الحرف، يمكنك استخدام الحلقة range.

package main

import "fmt"

func main() {
    s := "Hello, 世界"
    for index, runeValue := range s {
        fmt.Printf("%d: %U '%c'\n", index, runeValue, runeValue)
    }
    // الناتج: فهرس، الترميز اليونيكودي، والحرف نفسه لكل حرف
}

5.3.4 الحصول على الطول

يمكن لدالة len الحصول على طول السلسلة، أي طول السلسلة البايتية الأساسية. بالنسبة للسلاسل UTF-8، إذا كنت بحاجة إلى الحصول على عدد الأحرف (runes)، يجب عليك استخدام دالة utf8.RuneCountInString والتي تتعامل بشكل صحيح مع الأحرف متعددة البايتات.

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    s := "Hello, 世界"
    fmt.Println("طول البايتات:", len(s)) // المخرج: طول البايتات
    fmt.Println("طول الأحرف:", utf8.RuneCountInString(s)) // المخرج: عدد الأحرف
}

من المثال أعلاه، يُظهر لنا لغة Go توفر وظائف غنية لعمليات معالجة السلاسل النصية، مما يجعل من السهل إنجاز مهام معالجة السلاسل المختلفة. عند البرمجة، من المهم الانتباه إلى التمييز بين البايتات والأحرف، خاصة عند التعامل مع مجموعات الأحرف غير ASCII.