Menu
flag Ar iconالعربيةdown icon

المتغيّرات في Golang: var و:= والقيم الصفرية والتظليل

كيف تعرّف المتغيّرات في Go بـ var وبالصيغة المختصرة :=، وما هي القيم الصفرية، والإسناد المتعدّد، وأخطاء التظليل والمتغيّرات غير المستخدمة التي يقع فيها مبرمجو Go الجدد.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

لدى Go طريقتان لتعريف متغيّر: var، التي تعمل في أي مكان، و:=، صيغة مختصرة تعمل داخل الدوال وتستنتج النوع.

لكل متغيّر نوع ثابت يُحدَّد وقت الترجمة. عندما تعطي قيمة تستنتج Go النوع منها، فكتابة النوع أيضًا (var city string = "Lisbon") مسموحة لكنها زائدة.

var مقابل :=

var:=
أينمستوى الحزمة وداخل الدوالداخل الدوال فقط
النوعاختياري؛ ومطلوب عند غياب القيمةمستنتج دائمًا
القيمة الأوليةاختيارية (وإلا فالقيمة الصفرية)مطلوبة
إعادة التعريفأبدًامسموحة إذا كان متغيّر واحد على الأقل في الطرف الأول جديدًا

الاختيار المعتاد داخل دالة:

  • x := value عندما تكون لديك قيمة بداية.
  • var x T عندما تريد القيمة الصفرية، وهذا يشير إلى "فارغ عن قصد": var buf bytes.Buffer وvar total int.
  • var x T = value عندما لا يكون النوع المستنتج هو ما تريده، مثل var ratio float64 = 1 (أما ratio := 1 وحدها فستكون int).

:= خارج دالة خطأ صياغة:

./main.go:5:1: syntax error: non-declaration statement outside function body

القيم الصفرية

المتغيّر المعرّف دون قيمة لا يحمل قيمة عشوائية أبدًا. يحمل القيمة الصفرية لنوعه:

النوعالقيمة الصفرية
الأعداد الصحيحة والعشرية0
boolfalse
string""
المؤشرات والشرائح والخرائط والقنوات والدوال والواجهاتnil
المصفوفات والبنىكل عنصر أو حقل بقيمته الصفرية

الواجهات البرمجية الجيدة في Go مصمّمة لتكون القيمة الصفرية مفيدة: sync.Mutex الصفري غير مقفل، وbytes.Buffer الصفري فارغ وجاهز، وlen وrange وappend كلها تعمل مع شريحة nil. والنوع الذي يجب الانتباه له هو الخريطة: قراءة خريطة nil تعيد قيمًا صفرية، لكن الكتابة فيها تسبّب panic. أنشئ الخرائط بـ make أو بحرفية قبل التخزين فيها.

تعريف عدة متغيّرات

تجمع كتلة var ( ... ) المتغيّرات المرتبطة على مستوى الحزمة. في الإسناد المتعدّد مثل x, y = y, x يُقيَّم كل تعبير في الطرف الثاني قبل إسناد أي شيء، ولهذا يعمل التبديل.

لا تعيد := مع عدة أسماء تعريف أي شيء ما دام اسم واحد على الأقل في الطرف الأول جديدًا. الأسماء الموجودة في النطاق نفسه يُسند إليها ببساطة. وهذا ما يتيح لك إعادة استخدام err:

f, err := os.Open("a.txt")   // declares f and err
g, err := os.Open("b.txt")   // declares g, assigns to the existing err

إذا لم يكن أي من الأسماء جديدًا فهو خطأ:

./main.go:7:4: no new variables on left side of :=

استخدم = العادية للإسناد إلى متغيّر موجود.

المتغيّرات غير المستخدمة أخطاء

المتغيّر المحلي المعرّف الذي لا يُقرأ أبدًا يوقف البناء:

./main.go:9:2: declared and not used: x

ليس تحذيرًا يمكنك تعطيله. احذف المتغيّر، أو استخدمه، أو أثناء تتبّع الأخطاء أسكته بالمعرّف الفارغ: _ = x. ويتجاهل المعرّف الفارغ أيضًا القيم المعادة التي لا تحتاجها: _, err := fmt.Println("hi").

المتغيّرات على مستوى الحزمة ومعاملات الدوال مستثناة من هذه القاعدة.

النطاق والتظليل

يوجد المتغيّر من تعريفه حتى نهاية الكتلة المحيطة ({ ... }). تنشئ := في كتلة داخلية متغيّرًا جديدًا، حتى لو وُجد متغيّر بالاسم نفسه في الخارج. يُظلَّل الخارجي، ولا يتغيّر:

يطبع البرنامج inside: 42 ثم outside: 0. عرّفت := داخل if كلًا من count وerr كمتغيّرين جديدين في الكتلة الداخلية، لأن أيًا منهما لم يكن موجودًا هناك بعد. يُترجم هذا بلا مشكلة، وهو مصدر كلاسيكي لأخطاء "اختفت قيمتي".

الإصلاح أن تعرّف err أولًا وتسند بـ =:

var err error
count, err = strconv.Atoi(input)

لا يبلغ go vet عن التظليل افتراضيًا. يفعل ذلك المحلّل المنفصل shadow، ويمكن لأدوات الفحص مثل golangci-lint تفعيله.

التسمية

  • استخدم camelCase: maxRetries وuserID. لا max_retries.
  • أبقِ الاختصارات بحالة واحدة: userID وhttpClient وparseURL، لا userId.
  • أسماء قصيرة للنطاقات القصيرة: i في حلقة، وr لقارئ، وerr لخطأ. وأسماء أطول ووصفية للمتغيّرات على مستوى الحزمة.
  • الاسم الذي يبدأ بحرف كبير على مستوى الحزمة (var Timeout) مُصدَّر إلى الحزم الأخرى. راجع صفحة الحزم والاستيراد.

المتغيّرات على مستوى الحزمة

المتغيّرات المعرّفة خارج الدوال تعيش طوال البرنامج وتُهيّأ قبل تشغيل main، بترتيب الاعتماديات. وهي مريحة للإعدادات والذاكرات المؤقّتة، وتتشاركها كل الـ goroutines. إذا كتبت أكثر من goroutine في أحدها، فاحمه بـ mutex أو استخدم sync/atomic، وإلا فلديك سباق بيانات.

فضّل الثوابت للقيم التي لا تتغيّر أبدًا. لا يمكن تعديل const بالخطأ ولا يكلّف شيئًا وقت التشغيل.

الأسئلة الشائعة

ما الفرق بين var و:= في Go؟

تعرّف := متغيّرًا وتهيّئه بنوع مستنتج، ولا تعمل إلا داخل الدوال: count := 10. أما var فتعمل في كل مكان (بما في ذلك مستوى الحزمة)، وتتيح لك ذكر النوع، ويمكن أن تحذف القيمة الأولية لتحصل على القيمة الصفرية: var count int. داخل الدوال يستخدم أسلوب Go المعتاد := عندما توجد قيمة أولية وvar عندما تريد القيمة الصفرية.

ما هي القيم الصفرية في Go؟

كل متغيّر يُعرَّف دون قيمة يأخذ القيمة الصفرية لنوعه: 0 للأرقام، وfalse لـ bool، و"" لـ string، وnil للمؤشرات والشرائح والخرائط والقنوات والدوال والواجهات. وتأخذ البنى القيمة الصفرية لكل حقل. لا توجد متغيّرات غير مهيّأة في Go.

كيف أصلح خطأ "declared and not used" في Go؟

ترفض Go متغيّرًا محليًا يُسند إليه ولا يُقرأ أبدًا. استخدمه، أو احذفه، أو أثناء تتبّع الأخطاء أسنده إلى المعرّف الفارغ بـ _ = x. المتغيّرات على مستوى الحزمة ومعاملات الدوال مستثناة.

كيف أعرّف متغيّرًا عامًا في Go؟

استخدم var على مستوى الحزمة، خارج أي دالة: var counter int. الصيغة المختصرة := غير مسموحة هناك. الاسم الذي يبدأ بحرف كبير (var Counter int) مرئي للحزم الأخرى؛ والذي يبدأ بحرف صغير مرئي في حزمته فقط. احمِ المتغيّرات على مستوى الحزمة بـ mutex إذا كانت goroutines تكتب فيها.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن