Go تصدر إصدارًا رئيسيًا جديدًا كل ستة أشهر تقريبًا، والتزام Go الشهير بالتوافق العكسي (Go 1 compatibility promise) يعني أن كودك القديم يستمر يعمل دون أي تعديل. Go 1.27 (أغسطس 2026) جابت معها أول تغيير حقيقي على قواعد Generics منذ إدخالها بـ Go 1.18، بالإضافة لحزم جديدة بالمكتبة القياسية تستحق المعرفة.
Generic Methods — أول توسيع حقيقي لـ Generics
حتى Go 1.26، معامل النوع (type parameter) كان مسموحًا فقط بدالة كاملة بمستوى الحزمة، أو بنوع عام كامل (زي Stack[T]). الآن method مفرد يقدر يعلن معامل نوع خاص فيه، منفصل تمامًا عن النوع الذي يتبع له:
type Registry struct {
name string
}
// T هنا خاص بهذا الـ method فقط -- Registry نفسه نوع عادي غير عام
func (r Registry) Filter[T any](items []T, keep func(T) bool) []T {
var result []T
for _, item := range items {
if keep(item) {
result = append(result, item)
}
}
return result
}
r := Registry{name: "المستخدمون"}
r.Filter([]int{1, 2, 3, 4}, func(n int) bool { return n%2 == 0 }) // [2 4]
الفائدة العملية: تقدر تضيف عملية عامة لنوع موجود أصلًا بدون تحويل النوع كله إلى نوع عام — مفيد جدًا بمكتبات تصدّر أنواعًا محدَّدة (زي Registry بالمثال) وتريد إضافة دوال مساعدة عامة عليها دون كسر أي كود يستخدمها حاليًا.
قيد واحد مهم: methods الواجهات (interfaces) لا يمكن أن تعلن معامل نوع خاصًّا بها، لأن توقيع الواجهة لازم يكون ثابتًا وواحدًا — لا يتغيّر حسب T المُمرَّر وقت الاستدعاء.
حزمة encoding/json/v2 — بجانب القديمة، لا بدلًا منها
encoding/json القديمة تبقى مدعومة بالكامل — ما في إلزام ترحيل. لكن Go 1.27 أضافت حزمة موازية encoding/json/v2 بنفس فكرة Marshal و Unmarshal لكن بقواعد أدقّ:
import jsonv2 "encoding/json/v2"
data, err := jsonv2.Marshal(someValue)
err = jsonv2.Unmarshal(data, &target)
الفرق الجوهري: النسخة الثانية ترفض نصوص UTF-8 غير صالحة داخل قيم JSON، وترفض تكرار نفس المفتاح مرّتين بنفس الكائن — بدل تجاهل هذه الحالات بصمت كما تفعل النسخة الأولى. أداء unmarshal فيها أسرع ملحوظًا أيضًا. اختَرها لمشروع جديد يتعامل مع JSON من مصدر خارجي غير موثوق تمامًا؛ لا داعي للترحيل الفوري لكود يعمل بشكل صحيح بالنسخة القديمة.
حزمة uuid — توليد وتحليل UUID بلا مكتبة خارجية
قبل Go 1.27، توليد UUID كان يحتاج مكتبة خارجية (زي google/uuid). الآن الحزمة uuid جزء من المكتبة القياسية مباشرة:
import "uuid"
id := uuid.New() // UUID عشوائي (نسخة v4)
sortable := uuid.NewV7() // UUID مرتّب زمنيًا (نسخة v7) -- مفيد كمفتاح أساسي بقاعدة بيانات
parsed, err := uuid.Parse("f81d4fae-7dec-11d0-a765-00a0c91e6bf6")
fmt.Println(id.String())
NewV7 تحديدًا تستحق الانتباه: تولّد UUID يحمل طابعًا زمنيًا بالبتات الأولى، فتُرتَّب تصاعديًا تلقائيًا — أفضل لأداء الفهرسة بقاعدة بيانات من UUIDv4 العشوائي بالكامل الذي يبعثر الإدخالات بشكل عشوائي داخل الفهرس.
ملف تعقّب goroutines المتسرّبة — من تجريبي إلى جاهز للإنتاج
Go 1.26 قدّمت ملف تعقّب (profile) تجريبي باسم goroutineleak بحزمة runtime/pprof لاكتشاف goroutines عالقة للأبد بانتظار قناة أو sync.Mutex لن يتحرّر أبدًا. Go 1.27 اعتمدته رسميًا كميزة جاهزة للإنتاج، متاح أيضًا كمسار /debug/pprof/goroutineleak عبر net/http/pprof لأي خادم يعرض ملفات pprof.
دفعة تحسينات أصغر تستحق الذكر
| الإضافة | الفائدة |
|---|---|
strings.CutLast و bytes.CutLast | تقطيع نص/بايتات عند آخر ظهور لفاصل، مقابل Cut الذي يقطع عند أول ظهور |
| مفتاح struct literal لحقل مُرقّى (promoted) | يمكن الآن كتابة Outer{PromotedField: value} مباشرة لحقل من نوع مُضمَّن (embedded) بدون تعشيش النوع الداخلي، وحتى استخدام مسار مؤهَّل Embedded.Field عند وجود تعارض بالاسم |
crypto/mldsa | حزمة جديدة لخوارزمية توقيع ML-DSA المقاومة للحوسبة الكمّية (FIPS 204) — مخصّصة لسياقات تشفير متقدّمة |
الخلاصة
Go 1.27 ليست قفزة بحجم إدخال Generics نفسها، لكنها أول توسيع حقيقي لقواعدها منذ ذلك الحين، مع إضافات مكتبة قياسية عملية (uuid، json/v2) تقلّل الحاجة لمكتبات خارجية لمهام شائعة جدًا. لو تتعلّم Go من الصفر، ابدأ بالأساسيات — هذه الميزات تفيدك أكثر بعد إتقانها.