قرأت للتو مقالاً: 15 تفصيلاً دقيقاً في Go قد لا تعرفها بالفعل. بعد قراءة ذلك المقال، أشعر أن العنوان غريب/غير مناسب بعض الشيء. لأن كل ما يسمى تفاصيل دقيقة ورد في ذلك المقال هو مما ينبغي لمبرمج Go مؤهل أن يعرفه.
لدى Go بالفعل تفاصيل دقيقة كثيرة. وحتى كثير من مبرمجي Go المحترفين لا يدركون بعضها. وهنا يعرض هذا المقال عدة منها (وكلها من كتاب Go Details & Tips 101).
المحتويات:
- مقارنة مؤشرين إلى قيم صفرية الحجم قد تكون نتيجتها صحيحة أو خاطئة، حتى أثناء تنفيذ البرنامج نفسه
- for true {...} و for {...} ليستا متكافئتين
- عند استخدام دالة make المدمجة لإنشاء خريطة، يمكن أن يكون المعطى الثاني ( cap ) سالباً
- aConstantString[:] ليست ثابتاً
- إذا كان المعامَل به الأيسر في تعبير إزاحة بتات غير ثابت غير مُنمَّط، فيُحدَّد نوعه بالنوع المفترض للتعبير
مقارنة مؤشرين إلى قيم صفرية الحجم قد تكون نتيجتها صحيحة أو خاطئة، حتى أثناء تنفيذ البرنامج نفسه
على سبيل المثال. ماذا يطبع البرنامج التالي؟ لا شيء أم true؟
package main
var a, b [0]int
var p, q = &a, &b
func main() {
if (p == q) {
p, q = &a, &b
println(p == q)
}
}
يطبع false (مع سلسلة أدوات Go الرسمية). مفاجأة؟ لكن يبدو أن السلوك لا يخالف مواصفات Go.
مثال مشابه:
package main
var a, b struct{}
var p, q = &a, &b
func main() {
var p2, q2 = &a, &b
println(p == q) // true
println(p == p2) // true
println(q == q2) // true
println(p == q2) // true
println(q == p2) // true
println(p2 == q2) // false
}
for true {...} وfor {...} ليستا متكافئتين
على سبيل المثال، تُصرَّف الدالة foo الموضحة أدناه، لكن bar لا تُصرَّف.
func foo() int {
for {}
}
func bar() int {
for true {}
}
عند استخدام دالة make المدمجة لإنشاء خريطة، يمكن أن يكون المعطى الثاني (cap) سالباً
على سبيل المثال، تُصرَّف الشيفرة التالية.
package main
var n = -100
func main() {
var m = make(map[int]bool, n)
m[123] = true;
}
المعطى cap السالب مكافئ لحذفه.
aConstantString[:] ليست ثابتاً
إليك مثالاً يثبت ذلك.
package main
const s = "zigo 101" // len(s) == 8
var a byte = 1 << len(s) / 128
var b byte = 1 << len(s[:]) / 128
func main() {
println(a, b) // 2 0
}
قد يفاجأ بعض مبرمجي Go بهذه النتيجة. ولمعرفة سبب هذه النتيجة جيداً، نحتاج إلى معرفة التفصيل الدقيق التالي.
إذا كان المعامَل به الأيسر في تعبير إزاحة بتات غير ثابت غير مُنمَّط، فيُحدَّد نوعه بالنوع المفترض للتعبير
على سبيل المثال، يطبع البرنامج التالي 0 0 2.
package main
const N = 8
var n = N
func main() {
var x byte = 1 << n / 128
var y = byte(1 << n / 128)
var z byte = 1 << N / 128
println(x, y, z) // 0 0 2
}
في التعريفين الأولين، يُفترض أن نوع 1 هو byte في كلٍّ منهما. لذا فكلا التعريفين مكافئ للسطر التالي، حيث يتجاوز تعبير وقت التشغيل byte(1) << n حدوده (ويُقتطع إلى 0).
... = byte(1) << n // 128
التعريف الأخير مكافئ للسطر التالي. يُقيَّم التعبير 1 << N / 128 في وقت التصريف. وفي هذا التعبير، يُعامَل 1 كقيمة int غير مُنمَّطة.
var z = 2