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

الثوابت const في Golang: الثوابت ذات النوع وعديمة النوع

كيف تعمل const في Go: تعريف الثوابت، الفرق بين الثوابت ذات النوع وعديمة النوع، التعابير الثابتة بدقة غير محدودة، ولماذا لا تملك Go شرائح أو خرائط أو بنى ثابتة.

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

الثابت قيمة محدّدة وقت الترجمة. عرّفه بـ const، وسترفض Go أي محاولة لتغييره.

يمكن تعريف الثوابت على مستوى الحزمة أو داخل دالة، واحدًا في كل سطر أو مجمّعة في كتلة const ( ... ). يُحسب MB وGB من ثوابت أخرى، ويجري المترجم هذه العمليات الحسابية مرة واحدة وقت البناء.

الإسناد إلى ثابت، مثل MaxRetries = 5، خطأ ترجمة:

./main.go:8:2: cannot assign to MaxRetries (neither addressable nor a map index expression)

ما الذي يمكن أن يكون ثابتًا

ثلاثة أنواع من القيم فقط: القيم المنطقية، والأرقام (الأعداد الصحيحة والعشرية والمركّبة والـ runes) والنصوص. يجب أن يستطيع المترجم حساب القيمة، أي حرفيات وثوابت أخرى وعمليات حسابية عليها وبعض الدوال المدمجة مثل len على نص ثابت.

كل ما يحتاج إلى تشغيل شيفرة أو حجز ذاكرة مستبعد:

const Colors = []string{"red", "green"} // slice
const Started = time.Now()              // function call
./main.go:9:16: []string{…} (value of type []string) is not constant
./main.go:10:13: time.Now() (value of struct type time.Time) is not constant

لماذا لا تملك Go شرائح أو خرائط ثابتة

الشرائح والخرائط والبنى التي تحتويها مراجع إلى ذاكرة موجودة وقت التشغيل، فلا يستطيع المترجم تضمينها في البرنامج كقيم ثابتة، ولا تملك Go معدِّلًا مثل readonly أو final للمتغيّرات. الحلول الشائعة:

تكلّف النسخة حجز ذاكرة في كل استدعاء، وهذا مقبول لبيانات بحجم الإعدادات. للبحث بالمفتاح، عبارة switch داخل دالة خيار آخر يشبه الثابت: func statusText(code int) string { switch code { ... } }.

الثوابت عديمة النوع

الثابت المعرَّف دون نوع عديم النوع (untyped). له صنف (عدد صحيح، عشري، rune، نص، منطقي) لكن ليس له نوع Go محدد حتى يُستخدم، فيتكيّف مع السياق:

يعمل Ratio كـ int وfloat64 وuint8 وfloat32 دون تحويل. لهذا تُترجم time.Sleep(2 * time.Second): الرقم 2 عديم النوع ويصبح time.Duration.

عندما لا يفرض السياق نوعًا، كما في x := Ratio، يأخذ الثابت نوعه الافتراضي:

صنف الثابت عديم النوعالنوع الافتراضي
عدد صحيح (42)int
عدد عشري (4.2)float64
rune ('a')rune (int32)
عدد مركّب (2i)complex128
نصstring
منطقيbool

حساب دقيق

الثوابت الرقمية عديمة النوع دقيقة. يمثّل المترجم الأعداد الصحيحة بـ 256 بت على الأقل، فقد تكون القيم الوسيطة أكبر بكثير من أي نوع في Go:

لا يمكن طباعة Huge نفسه كعدد صحيح، لأن تمريره إلى fmt.Println يحوّله إلى int، ويكتشف المترجم ذلك (float64(Huge) تعمل، لأن العدد العشري يتّسع لهذا المقدار):

cannot use Huge (untyped int constant 1267650600228229401496703205376) as int value in argument to fmt.Println (overflows)

الفحص نفسه يوقف أخطاء أصغر وقت الترجمة، مثل var b byte = 300:

cannot use 300 (untyped int constant) as byte value in variable declaration (overflows)

الثوابت ذات النوع

أعطِ الثابت نوعًا فيتصرّف كقيمة من ذلك النوع في كل مكان، بما في ذلك رفض Go خلط الأنواع:

const Limit int = 10

var f float64 = 2
fmt.Println(Limit * f)
invalid operation: Limit * f (mismatched types int and float64)

مع const Limit = 10 (عديم النوع) تُترجم Limit * f وتعطي 20. لذا اترك الثوابت عديمة النوع ما لم يحمل النوع معنى. ويحمل معنى عندما تعرّف ثوابت من نوعك المسمّى الخاص، وهي الطريقة التي تبني بها Go التعدادات:

type Weekday int

const (
	Sunday Weekday = iota
	Monday
	Tuesday
)

هنا النوع هو المقصود: الدالة التي تأخذ Weekday توثّق ما تريده. صفحة التعدادات وiota تشرح iota وأنماط التعدادات المبنية عليها.

const مقابل var

constvar
يمكن تغييرهلانعم
معرفة القيمةوقت الترجمةوقت التشغيل
الأنواع المسموحةمنطقي، رقمي، نصأي نوع
يشغل ذاكرة وقت التشغيللانعم
يمكن أخذ عنوانه (&x)لانعم
غير المستخدم منه خطألانعم، للمتغيّرات المحلية

استخدم const لكل ما هو ثابت فعلًا: الحدود والأحجام والأسماء ورموز البروتوكولات ونصوص التنسيق. تحصل على فحص الفيضان وقت الترجمة وحساب دقيق دون أي كلفة.

مزالق

الثوابت ذات النوع لا تتكيّف. لا يمكن تمرير const Timeout int = 5 حيث يُتوقَّع time.Duration دون تحويل؛ أما const Timeout = 5 عديم النوع فيمكن ضربه: Timeout * time.Second.

القسمة الصحيحة تحدث على الثوابت الصحيحة. قيمة const Half = 1 / 2 هي 0، لأن المعاملين عددان صحيحان عديما النوع. اكتب 1.0 / 2 لتحصل على 0.5.

لا عنوان. &MaxRetries لا تُترجم. إذا طلبت واجهة برمجية *int، انسخ الثابت إلى متغيّر أولًا.

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

كيف تعرّف ثابتًا في Go؟

بـ const: const MaxRetries = 3 أو بنوع صريح const Timeout time.Duration = 5 * time.Second. اجمع عدة ثوابت في كتلة: const ( A = 1; B = 2 ). يجب أن تكون القيمة قابلة للحساب وقت الترجمة.

هل يمكنني إنشاء شريحة أو خريطة أو مصفوفة ثابتة في Go؟

لا. الثوابت تكون فقط قيمًا منطقية وأرقامًا (ومنها الـ runes) ونصوصًا. const Colors = []string{"red"} تفشل برسالة is not constant. استخدم var على مستوى الحزمة، وإذا كان المستدعون لا يجب أن يعدّلوها فوفّر دالة تعيد نسخة جديدة.

ما هو الثابت عديم النوع في Go؟

ثابت يُعرَّف دون نوع، مثل const Pi = 3.14159. لا يملك نوعًا محددًا حتى يُستخدم، فيعمل الثابت نفسه كـ float32 أو float64 أو كـ int إن سمحت قيمته. والثوابت عديمة النوع دقيقة أيضًا: يحتفظ المترجم بـ 256 بت على الأقل من الدقة، فتكون const Big = 1 << 100 صالحة ما دمت تستخدمها فقط في تعابير تتسع نتائجها.

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

الـ const ثابت وقت الترجمة ولا يتغيّر أبدًا؛ لا يشغل ذاكرة وقت التشغيل ولا يحمل إلا قيمة منطقية أو رقمًا أو نصًا. أما var فموقع في الذاكرة يمكن إعادة الإسناد إليه ويحمل أي نوع، بما في ذلك القيم المحسوبة وقت التشغيل مثل time.Now().

Coddy programming languages illustration

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

ابدأ الآن