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

الدوال المتغيّرة العدد في Golang: معاملات ...T ونشر s...

تقبل الدالة المتغيّرة العدد (variadic) في Go أي عدد من الوسائط الأخيرة من نوع واحد. تعلّم صياغة ...T، وكيف تمرّر شريحة بـ s...، وفخ المشاركة، وكيف تستخدم fmt.Println الصيغة ...any.

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

المعامل ...T

ضع ... قبل نوع المعامل الأخير. يستطيع المستدعون عندها تمرير أي عدد من الوسائط من ذلك النوع، بما في ذلك لا شيء. وداخل الدالة يكون المعامل شريحة.

يطبع هذا 0 و5 و10. دون وسائط تكون nums شريحة nil طولها 0، فلا تُنفَّذ الحلقة ببساطة.

يمكن أن تأتي المعاملات العادية أولًا. والأخير وحده يمكن أن يكون متغيّر العدد:

func logf(level string, format string, args ...any)

تمرير شريحة بـ s...

إذا كانت لديك شريحة أصلًا فلا يمكنك تمريرها مباشرة: تفشل sum(nums) برسالة cannot use nums (variable of type []int) as int value in argument to sum. انشرها بـ ... بعد الوسيط:

append متغيّرة العدد أيضًا، ولهذا يكون ضمّ شريحتين append(a, b...).

يجب أن يكون النشر الشيء الوحيد في الموضع المتغيّر العدد. تفشل sum(1, nums...) برسالة too many arguments in call to sum. ابنِ الشريحة المدمجة أولًا بـ append.

الشريحة مشتركة لا منسوخة

عندما تستدعي بوسائط مفردة تنشئ Go شريحة جديدة لها. وعندما تنشر شريحة موجودة بـ s... تتلقّى الدالة الشريحة نفسها. والكتابة في عناصرها تغيّر بيانات المستدعي.

المخرجات:

[7 8 9]
[0 8 9]

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

...any وكيف تعمل fmt.Println

تُعرَّف fmt.Println بالشكل func Println(a ...any) (n int, err error). يقبل any (اسم بديل لـ interface{} منذ Go 1.18) كل نوع، فتستطيع تمرير نصوص وأرقام وبنى في استدعاء واحد.

التمرير هو التفصيلة المهمّة: تمرّر logf القيمة args... إلى Printf. دون النقاط تتلقّى Printf وسيطًا واحدًا، []any، فيطبع سطر التحذير [WARN] [3 8] of %!d(MISSING) workers idle. لا يبلغ go vet عن missing ... in args forwarded to printf-like function إلا عندما يُمرَّر معامل التنسيق دون تغيير، كما في fmt.Printf(format, args). أما هنا فالتنسيق مبني بـ +، فيصمت vet والنقاط مسؤوليتك.

لا يمكن نشر []string في ...any. يجب أن تتطابق أنواع العناصر بالضبط، فحوّل أولًا:

names := []string{"a", "b"}
args := make([]any, len(names))
for i, n := range names {
	args[i] = n
}
fmt.Println(args...)

اشتراط وسيط واحد على الأقل

يقبل المعامل المتغيّر العدد صفر وسائط. عندما تحتاج الدالة وسيطًا واحدًا على الأقل، اجعل الأول معاملًا عاديًا:

صارت maxOf() الآن خطأ ترجمة بدل فحص وقت التشغيل. والدالة المدمجة max نفسها تعمل بالطريقة ذاتها: تتطلّب وسيطًا واحدًا على الأقل.

المعاملات المتغيّرة العدد كوسائط اختيارية

لا تملك Go قيمًا افتراضية للمعاملات. يُستخدم المعامل المتغيّر العدد أحيانًا لمحاكاة وسيط اختياري واحد:

func connect(addr string, timeout ...time.Duration)

يعمل هذا لكنه يُقرأ بشكل سيئ، لأن المستدعين يستطيعون تمرير ثلاث مهل ولا يقول التوقيع أيها يفوز. لأكثر من خيار واحد فضّل بنية إعدادات، أو نمط الخيارات الوظيفية (...Option، حيث كل Option دالة تضبط حقلًا). هذا النمط متغيّر العدد، لكن لكل وسيط معنى واضح.

مرجع القواعد

القاعدةمثال
المعامل الأخير وحده يمكن أن يكون متغيّر العددfunc f(a string, b ...int)
في الداخل يكون المعامل شريحةنوع b هو []int
صفر وسائط يعطي شريحة nilf("x") تجعل b == nil
انشر شريحة بـ ...f("x", nums...)
النشر يشارك المصفوفة الخلفيةالكتابة في b[i] تغيّر nums
لا خلط للنشر مع قيم إضافيةf("x", 1, nums...) لا تُترجم

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

ما هي الدالة المتغيّرة العدد في Go؟

دالة معاملها الأخير على الشكل ...T، مثل func sum(nums ...int) int. يمكن استدعاؤها بصفر وسائط أو أكثر من النوع T، وداخل الدالة يكون المعامل شريحة []T.

كيف أمرّر شريحة إلى دالة متغيّرة العدد في Go؟

أضف ... بعد الشريحة: sum(nums...). تُمرَّر الشريحة كما هي دون نسخ، فترى الدالة المصفوفة الخلفية نفسها. لا يمكنك خلط النشر مع وسائط مفردة: sum(1, nums...) لا تُترجم.

هل تملك Go معامل نشر (spread)؟

فقط للوسيط الأخير في استدعاء دالة متغيّرة العدد: f(s...). لا يوجد نشر عام لبناء المصفوفات أو البنى، أو لاستدعاء دوال غير متغيّرة العدد بشريحة. وappend(a, b...) هي القاعدة نفسها مطبّقة على الدالة المدمجة append.

هل يمكن أن يكون لدالة في Go معاملان متغيّرا العدد؟

لا. المعامل الأخير وحده يمكن أن يكون متغيّر العدد، وواحد فقط لكل دالة. مرّر القوائم الإضافية كمعاملات شرائح عادية.

Coddy programming languages illustration

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

ابدأ الآن