دالة متغيرة

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

ملخص

هناك العديد من العمليات الرياضية والمنطقية التي تبدو بشكل طبيعي كدوال متغيرة. على سبيل المثال، جمع الأرقام أو دمج السلاسل النصية أو غيرها من التسلسلات هي عمليات يمكن اعتبارها قابلة للتطبيق على أي عدد من المعاملات (على الرغم من أنه يتم تطبيق خاصية التجميع رسميًا في هذه الحالات ).

من العمليات الأخرى التي تم تنفيذها كدالة متعددة الوسائط في العديد من لغات البرمجة هي تنسيق المخرجات. تُعد دالة Cprintf ودالة Common Lispformat مثالين على ذلك. تأخذ كلتاهما وسيطًا واحدًا يحدد تنسيق المخرجات، وأي عدد من الوسائط التي توفر القيم المراد تنسيقها.

قد تُعرّض الدوال ذات الوسائط المتغيرة بعض لغات البرمجة لمشاكل تتعلق بسلامة أنواع البياناتprintf . على سبيل المثال، في لغة C ، قد يؤدي استخدامها بشكل غير حذر إلى ظهور نوع من الثغرات الأمنية المعروفة باسم هجمات سلاسل التنسيق . يُمكن حدوث هذا الهجوم لأن دعم اللغة للدوال ذات الوسائط المتغيرة ليس آمنًا من ناحية أنواع البيانات، إذ يسمح للدالة بمحاولة سحب عدد من الوسائط من المكدس يفوق العدد المُخزّن فيه، مما يُؤدي إلى تلف المكدس وسلوك غير متوقع. ونتيجةً لذلك، يعتبر مركز تنسيق الاستجابة لحوادث أمن الحاسوب (CERT) الدوال ذات الوسائط المتغيرة في لغة C خطرًا أمنيًا بالغ الخطورة. [ 1 ]

في لغات البرمجة الوظيفية ، تُعتبر الدوال ذات الوسائط المتغيرة مكملة للدالة ` apply` ، التي تأخذ دالة وقائمة/متسلسلة/مصفوفة كوسائط، وتستدعي الدالة بالوسائط المُقدمة في تلك القائمة، وبالتالي تُمرر عددًا متغيرًا من الوسائط إلى الدالة. في لغة البرمجة الوظيفية Haskell ، يُمكن تنفيذ الدوال ذات الوسائط المتغيرة عن طريق إرجاع قيمة من نوع `class` ؛ إذا كانت `class` هي القيمة النهائية المُرجعة ودالة ، فإن هذا يسمح بأي عدد من الوسائط الإضافية .TTr(T t) => x -> tx

يُطلق على موضوع ذي صلة في أبحاث إعادة كتابة المصطلحات اسم "التحوطات " أو " متغيرات التحوط ". [ 2 ] على عكس الدوال ذات الوسائط المتعددة، وهي دوال ذات وسائط، فإن التحوطات عبارة عن سلاسل من الوسائط نفسها. كما يمكن أن تخضع لقيود (مثل "لا تأخذ أكثر من 4 وسائط") لدرجة أنها لا تكون متغيرة الطول (مثل "خذ 4 وسائط بالضبط") - لذا فإن تسميتها بالدوال ذات الوسائط المتعددة قد يكون مضللاً. ومع ذلك، فإنها تشير إلى الظاهرة نفسها، وأحيانًا يختلط التعبير، مما ينتج عنه أسماء مثل " المتغير ذو الوسائط المتعددة" (مرادف لكلمة "تحوط"). لاحظ المعنى المزدوج لكلمة "متغير" والفرق بين الوسائط والمتغيرات في البرمجة الوظيفية وإعادة كتابة المصطلحات. على سبيل المثال، يمكن أن يحتوي مصطلح (دالة) على ثلاثة متغيرات، أحدها تحوط، مما يسمح للمصطلح بأخذ ثلاثة وسائط أو أكثر (أو اثنين أو أكثر إذا كان يُسمح للتحوط بأن يكون فارغًا).

أمثلة

ج

لتنفيذ الدوال المتغيرة الوسائط بشكل قابل للنقل في لغة C<stdarg.h> ، يُستخدم ملف الرأس القياسي . <varargs.h>وقد تم إيقاف استخدام ملف الرأس القديم لصالح ملف رأس آخر. في لغة C++، يُستخدم <stdarg.h>ملف الرأس . [ 3 ]<cstdarg>

#include <stdarg.h> #include <stdio.h>دالة متوسط ​​مزدوج ( عدد صحيح ، ...) { قائمة القيم الافتراضية ap ؛ مجموع مزدوج = 0 ؛va_start ( ap , count ); // قبل C23: يتطلب آخر مُعامل ثابت (للحصول على العنوان) for ( int j = 0 ; j < count ; ++ j ) { sum += va_arg ( ap , int ); // يزيد ap إلى المُعامل التالي } va_end ( ap );أعد المجموع / العدد ؛ }int main ( int argc , char * argv []) { printf ( "%f \n " , average ( 3 , 1 , 2 , 3 )); return 0 ; }

ستحسب هذه الدالة متوسط ​​عددٍ عشوائي من الوسائط. لاحظ أن الدالة لا تعرف عدد الوسائط أو أنواعها. تتوقع الدالة المذكورة أعلاه أن تكون الأنواع هي int، وأن يتم تمرير عدد الوسائط في الوسيط الأول (وهذا استخدام شائع، ولكنه ليس إلزاميًا في لغة البرمجة أو المُصرّف). في بعض الحالات الأخرى، مثل دالة printf ، يتم تحديد عدد الوسائط وأنواعها من سلسلة التنسيق. في كلتا الحالتين، يعتمد ذلك على المبرمج لتوفير المعلومات الصحيحة. (بدلاً من ذلك، يمكن استخدام قيمة مرجعية مثل NULLأو nullptrللإشارة إلى نهاية قائمة الوسائط). إذا تم تمرير عدد أقل من الوسائط مما تتوقعه الدالة، أو كانت أنواع الوسائط غير صحيحة، فقد يؤدي ذلك إلى قراءة مناطق غير صالحة من الذاكرة، مما قد يُسبب ثغرات أمنية مثل هجوم سلسلة التنسيق . اعتمادًا على النظام، حتى استخدام NULLكقيمة مرجعية قد يُواجه مثل هذه المشاكل؛ nullptrأو يمكن استخدام مؤشر فارغ مخصص من النوع المستهدف الصحيح لتجنبها.

stdarg.hيُعلن عن نوع، va_listويُعرّف أربعة وحدات ماكرو: va_start، va_arg، va_copy، و . يجب أن يُقابل va_endكل استدعاء لـ va_startو باستدعاء مُناسب لـ . عند التعامل مع وسائط متغيرة، تُعلن الدالة عادةً عن متغير من النوع ( في المثال) الذي ستتعامل معه وحدات الماكرو.va_copyva_endva_listap

  1. va_startتأخذ هذه الدالة وسيطين: va_listكائنًا ومرجعًا إلى آخر وسيط لها (الوسيط الذي يسبق علامة الحذف؛ يستخدمه الماكرو لتحديد اتجاهه). في C23 ، لن يكون الوسيط الثاني مطلوبًا، ولن تحتاج الدوال ذات الوسائط المتغيرة إلى وسيط مُسمى قبل علامة الحذف. [ ملاحظة 1 ] [ 5 ] تُهيئ هذه va_listالدالة الكائن لاستخدامه بواسطة va_argأو va_copy. عادةً ما يُصدر المُصرّف تحذيرًا إذا كان المرجع غير صحيح (مثل مرجع إلى وسيط مختلف عن الأخير، أو مرجع إلى كائن مختلف تمامًا)، ولكنه لن يمنع اكتمال عملية التجميع بشكل طبيعي.
  2. va_argتأخذ هذه الدالة وسيطين: va_listكائن (تمت تهيئته مسبقًا) ووصف نوع. تتوسع الدالة لتشمل الوسيط المتغير التالي، ويكون من النوع المحدد. va_argتسمح الاستدعاءات المتتالية بمعالجة كل وسيط متغير على حدة. يحدث سلوك غير محدد إذا كان النوع غير صحيح أو لم يكن هناك وسيط متغير تالٍ.
  3. va_endتأخذ هذه الدالة وسيطًا واحدًا، وهو va_listكائن. وتتمثل وظيفتها في تنظيف البيانات. فإذا أراد المبرمج، على سبيل المثال، فحص الوسائط المتغيرة أكثر من مرة، فسيعيد تهيئة الكائن va_listعن طريق استدعاء الدالة va_endثم إعادة تهيئته va_startمرة أخرى.
  4. va_copyتأخذ هذه الدالة وسيطين، كلاهما va_listكائنات. تقوم بنسخ الكائن الثاني (الذي يجب تهيئته مسبقًا) إلى الكائن الأول. بالعودة إلى مثال "مسح الوسائط المتغيرة أكثر من مرة"، يمكن تحقيق ذلك باستدعاء الدالة va_startالأولى على الكائن الأول va_list، ثم استخدام va_copyالدالة الثانية لنسخه إلى الكائن الثاني va_list. بعد مسح الوسائط المتغيرة للمرة الأولى باستخدام va_argالدالة الأولى va_list(والتخلص منها باستخدام الدالة الثانية va_end)، يمكن للمبرمج مسح الوسائط المتغيرة للمرة الثانية باستخدام الدالة الأولى va_argعلى الكائن الثاني va_list. va_endيجب أيضًا استدعاء الدالة الثانية على الكائن المنسوخ va_listقبل أن تُنهي الدالة الحاوية عملها.

سي شارب

تصف لغة C# الدوال ذات عدد الوسائط المتغير باستخدام الكلمة paramsالمفتاحية `variadic`. يجب تحديد نوع الوسائط، مع object[]إمكانية استخدام `variadic` كحل شامل. عند استدعاء الدالة، يمكنك إما سرد الوسائط واحدًا تلو الآخر، أو تمرير مصفوفة موجودة مسبقًا تحتوي على نوع العناصر المطلوب. استخدام صيغة `variadic` هو اختصار برمجي للخيار الأخير.

namespace Wikipedia.Examples ;باستخدام النظام ؛public class Program { static int Foo ( int a , int b , params int [] args ) { // إرجاع مجموع الأعداد الصحيحة في args، مع تجاهل a و b. int sum = 0 ; foreach ( int i in args ) { sum += i ; } return sum ; } static void Main ( string [] args ) { Console . WriteLine ( Foo ( 1 , 2 )); // 0 Console . WriteLine ( Foo ( 1 , 2 , 3 , 10 , 20 )); // 33 int [] manyValues ​​= [ 13 , 14 , 15 ]; Console . WriteLine ( Foo ( 1 , 2 , manyValues ​​)); // 42 } }

لغة سي++

تتشابه آلية التعامل مع الوسائط المتغيرة الأساسية في لغة C++ إلى حد كبير مع نظيرتها في لغة C. قبل إصدار C++26 ، كان بالإمكان حذف الفاصلة قبل علامة الحذف. كما تسمح C++ باستخدام الدوال ذات الوسائط المتغيرة بدون وسائط مُسماة (على سبيل المثال، `function` ). مع ذلك، لم تكن هناك طريقة موحدة للوصول إلى هذه الوسائط حتى إصدار C++26، لأن ` function` كان يتطلب اسم آخر وسيط ثابت للدالة. منذ إصدار C++26، اعتمدت C++ صيغة الوسيط الواحد `function` ، بما يتوافق مع معيار C23، مما يسمح بالوصول إلى الوسائط حتى عندما لا تحتوي الدالة على وسائط ثابتة.voidf(...);va_startva_start

يمكن أيضًا استخدام القوالب ذات المعاملات المتغيرة (حزمة المعاملات) في لغة C++ مع تعابير الطي المدمجة في اللغة . تُعدّ القوالب ذات المعاملات المتغيرة الطريقة الوحيدة الآمنة من حيث النوع للحصول على دوال/معاملات ذات معاملات متغيرة في C++، نظرًا لافتقار C++ إلى المعاملات المتغيرة غير القائمة على القوالب على غرار Java.

استيراد std ؛template < typename ... Ts > void fooPrint ( Ts ... args ) { (( std :: print ( "{} " , args )), ...); }int main ( int argc , char * argv []) { fooPrint ( 1 , 3.14f ); // 1 3.14 fooPrint ( "Foo" , 'b' , true , nullptr ); // Foo b true nullptr }

تُفضّل معايير CERT البرمجية للغة C++ بشدة استخدام القوالب المتغيرة (حزمة المعاملات) في C++ على الدوال المتغيرة على نمط C، وذلك لانخفاض مخاطر إساءة استخدامها. [ 6 ] تُعدّ القوالب المتغيرة الطريقة الوحيدة لتحقيق معاملات متغيرة آمنة من حيث النوع على نمط Java.

لتقييد المعامل ليكون من نوع معين فقط T(على غرار ) في جافا، يمكن استخدام المفهوم [ 7 ] أو ( للأنواع التي قد يُراد تحويلها). [ 8 ]T...argsstd::same_as<T, U>std::convertible_to<From, To>

باستخدام std :: same_as ؛// مكافئ لتصريح جافا // <T> void fn(T... args) template < typename T > void fn ( same_as < T > auto ... args ) { // ... }

الكربون

توفر لغة Carbon ، المصممة مع مراعاة التوافق مع لغة C++، إمكانية استخدام المتغيرات، وخاصة توسيعات الحزم. [ 9 ]

// تأخذ عددًا غير محدد من المتجهات بأنواع عناصر غير محددة، // وتعيد متجهًا من الأزواج حيث يكون العنصر رقم i من المتجه // زوجًا من العناصر رقم i من متجهات الإدخال. fn Zip [ ... eachElementType :! type ] ( ... eachvector : Vector ( eachElementType ) ) -> Vector (( ... eachElementType ) ) { ... var eachiter : auto = eachvector.Begin ( ); var result : Vector ( ( ... eachElementType ) ) ; while ( ... andeachiter ! = eachvector.End ( ) ) { result.push_back ( ( ... eachiter ) ) ; ... eachiter ++ ; } return result ; }

فورتران

منذ إصدار Fortran 90، أصبحت دوال أو إجراءات Fortran الفرعية تقبل وسائط اختيارية: [ 10 ] لا تزال قائمة الوسائط ثابتة، ولكن optionalيمكن حذف الوسائط التي تحمل السمة الاختيارية من استدعاء الدالة/الإجراء الفرعي. يمكن استخدام الدالة المضمنة present()للكشف عن وجود وسيط اختياري. يمكن أن تظهر الوسائط الاختيارية في أي مكان في قائمة الوسائط.

اختبار البرنامج ضمني لا شيءreal :: x !> يتم تمرير جميع الوسائط: call foo ( 1 , 2 , 3.0 , 4 , x ) !< يُخرج 1 \ 2 \ 3.0 \ 4 \ 6.0 (يشير "\" إلى سطر جديد) !> يتم حذف آخر وسيطين: call foo ( 1 , 2 , 3.0 ) !< يُخرج 1 \ 2 \ 3.0 !> يتم حذف الوسيطين الثاني والرابع: الوسائط التي تقع بعد !> يجب تمرير وسيط محذوف باستخدام كلمة مفتاحية: call foo ( 1 , c = 3.0 , e = x ) !< يُخرج 1 \ 3.0 \ 6.0 !> بدلاً من ذلك، قدمت مراجعة Fortran 2023 .NIL. يُستخدم الرمز !> للدلالة على وسيط محذوف. استدعاء الدالة foo ( 1 , . NIL ., 3.0 , . NIL ., x ) !< يُخرج القيمة 1 \ 3.0 \ 6.0يتضمن!> يحتوي الروتين الفرعي foo() على وسيطين إلزاميّين وثلاثة وسائط اختيارية. الروتين الفرعي foo ( a , b , c , d , e ) عدد صحيح ، غرض ( in ) : :: a عدد صحيح ، غرض ( in اختياري : :: b عدد حقيقي ، غرض ( in ) : :: c عدد صحيح ، غرض ( in اختياري : :: d عدد حقيقي ، غرض ( out اختياري : :: e اطبع * ، a إذا كان (b موجودًا ) اطبع * ، b اطبع * ، c إذا كان ( d موجودًا ) اطبع * ، d إذا كان ( e موجودًا ) إذن e = 2 * c اطبع * ، c نهاية الشرط نهاية  الروتين الفرعينهاية البرنامج

يذهب

يمكن استدعاء الدوال ذات الوسائط المتعددة في لغة Go بأي عدد من الوسائط اللاحقة. [ 11 ]fmt.Println هي دالة شائعة ذات وسائط متعددة؛ تستخدم واجهة فارغة كنوع شامل.

الحزمة الرئيسيةاستيراد "fmt"// تأخذ هذه الدالة ذات عدد الوسائط المتغير عددًا غير محدد من الأعداد الصحيحة كوسيطات. func sum(nums...int) { fmt.Print ( " مجموع " , nums ) // دالة ذات عدد وسائط متغير أيضًا . total : = 0 for _ , num : = range nums { total + = num } fmt.Println ( " هو " , total ) // دالة ذات عدد وسائط متغير أيضًا. }func main () { // يمكن استدعاء الدوال ذات الوسائط المتغيرة بالطريقة المعتادة باستخدام وسائط فردية. sum ( 1 , 2 ) // "مجموع [1 2] هو 3" sum ( 1 , 2 , 3 ) // "مجموع [1 2 3] هو 6"// إذا كان لديك بالفعل عدة وسائط في شريحة، فقم بتطبيقها على دالة متعددة الوسائط باستخدام func(slice...) كما يلي. nums := [] int { 1 , 2 , 3 , 4 } sum ( nums ... ) // "مجموع [1 2 3 4] هو 10" }

الناتج:

مجموع [1 2] هو 3 مجموع [1 2 3] هو 6 مجموع [1 2 3 4] هو 10 

جافا

كما هو الحال مع لغة C#، فإن Objectالنوع في لغة Java متاح كنوع شامل.

في لغة جافا، يمكن أن يكون المعامل متغير الوسائط باستخدام رمز الحذف (...). وهذا يُعادل تقريبًا المصفوفة، ولكنه لا يتطلب تغليفه كمصفوفة. على سبيل المثال، سيكون المعاملان متطابقين تقريبًا String... args.String[] args

package org.wikipedia.examples ;public class Program { // تخزن الدوال ذات الوسائط المتعددة أي وسائط إضافية تستقبلها في مصفوفة. // وبالتالي، فإن `printArgs` هي في الواقع دالة ذات وسيط واحد: // مصفوفة متغيرة الطول من `String`. private static void printArgs ( String ... strings ) { for ( String s : strings ) { System . out . println ( s ); } }public static void main ( String [] args ) { printArgs ( "hello" ); // اختصار لـ printArgs(new String[] {"hello"}) printArgs ( "hello" , "world" ); // اختصار لـ printArgs(new String[] {"hello", "world"}) printArgs ( args ); // يطبع مصفوفة args بالكامل } }

جافا سكريبت

لا تهتم لغة جافا سكريبت بأنواع الوسائط المتغيرة. يُرمز للوسيط المتغير بالرمز `variadic` ...، والذي يُشير إلى "معامل متبقٍ" يجمع الوسائط في مصفوفة.

دالة الجمع (... أرقام ) { إرجاع أرقام . تقليل (( أ ، ب ) => أ + ب ، 0 }console.log ( sum ( 1 , 2 , 3 ) ); // 6 console.log ( sum ( 3 , 2 ) ); // 5 console.log ( sum ( ) ) ; // 0

من الممكن أيضًا إنشاء دالة متغيرة الوسائط باستخدام كائن الوسائط، على الرغم من أنه لا يمكن استخدامه إلا مع الدوال التي تم إنشاؤها باستخدام functionالكلمة المفتاحية.

دالة الجمع ( ) { إرجاع Array.prototype.reduce.call ( arguments , ( a , b ) = > a + b , 0 ) ; }console.log ( sum ( 1 , 2 , 3 ) ); // 6 console.log ( sum ( 3 , 2 ) ); // 5 console.log ( sum ( ) ) ; // 0

لاحظ أنه في لغة TypeScript ، ولأن المعامل rest عبارة عن مصفوفة، يتم الإشارة إلى ذلك على النحو التالي:

دالة الجمع ( ...أعداد : عدد []) : عدد { إرجاع أعداد . تقليل (( أ ، ب ) => أ + ب ، 0 ); }

يسمح TypeScript أيضًا بفرض أن يكون للمعامل المتبقي عدد محدد من العناصر (أي مجموعة):

// دالة تُجبر على الحصول على ثلاثة أعداد بالضبط : sumExactlyThree (... numbers : [ number , number , number ]) : number { return numbers . reduce (( a , b ) => a + b , 0 ); }// دالة تُجبر على الحصول على عددين على الأقل: sumAtLeastTwo (... numbers : [ number , number , ... number []]) : number { return numbers . reduce (( a , b ) => a + b , 0 ); }// يجبر الوسيط الأول على أن يكون سلسلة نصية، ثم أي شيء بعده. دالة log (... args : [ string , ... any []]) { // ... }

لغة لوا

يمكن لدوال Lua تمرير الوسائط المتغيرة (varargs) إلى دوال أخرى بنفس طريقة تمرير القيم الأخرى باستخدام الكلمة returnالمفتاحية `varargs`. ويمكن تمرير الجداول إلى الدوال ذات الوسائط المتغيرة باستخدام `varargs`، في Lua الإصدار 5.2 أو أحدث [ 12 ]table.unpack ، أو Lua الإصدار 5.1 أو أقدم [ 13 ]unpack . ويمكن استخدام الوسائط المتغيرة كجدول عن طريق إنشاء جدول باستخدام الوسيط المتغير كقيمة.

دالة sum (...) --... تُشير إلى الوسائط المتغيرة local sum = 0 for _ , v in pairs ({...}) do -- إنشاء جدول باستخدام وسائط متغيرة هو نفسه إنشاء جدول باستخدام القيم القياسية sum = sum + v end return sum endالقيم = { 1 , 2 , 3 , 4 } مجموع ( 5 , table.unpack ( القيم )) -- تُرجع 15. يجب أن تأتي table.unpack بعد أي وسيطات أخرى، وإلا فلن يتم تمرير جميع القيم إلى الدالة.دالة add5 (...) تُرجع ... + 5 -- هذا استخدام غير صحيح للوسائط المتغيرة، وستُرجع الدالة القيمة الأولى المُقدمة فقط .entries = {} function process_entries () local processed = {} for i , v in pairs ( entries ) do processed [ i ] = v -- كود معالجة مؤقت end return table.unpack ( processed ) -- تُرجع جميع الإدخالات بطريقة يمكن استخدامها كمتغير vararg endprint ( process_entries ()) -- تقوم دالة الطباعة بأخذ جميع الوسائط المتغيرة وكتابتها إلى الإخراج القياسي مفصولة بأسطر جديدة

باسكال

لغة باسكال موحدة وفقًا لمعياري ISO 7185 ("باسكال القياسية") و10206 ("باسكال الموسعة"). لا يدعم أي من الشكلين القياسيين لباسكال الإجراءات ذات عدد متغير من الوسائط، باستثناء بعض الإجراءات المدمجة ( readمثل / readLnو write/ writeLn، بالإضافة إلى / في باسكال الموسعة ).readStrwriteStr

مع ذلك، تُطبّق لهجات باسكال آليات تُشبه الإجراءات ذات الوسائط المتغيرة. تُعرّف دلفي نوع بيانات يُمكن ربطه بالمعامل الرسمي الأخير . ضمن تعريف الإجراء، يكون هذا المعامل عبارة عن مصفوفة من السجلات المتغيرة . [ 14 ] يسمح عنصر نوع البيانات المذكور بفحص نوع بيانات الوسيط ومعالجته بالشكل المناسب. يدعم مُصرّف فري باسكال أيضًا إجراءات دلفي ذات الوسائط المتغيرة. [ 15 ]arrayofconstarrayofconstarrayofTVarRecVTyperecord

مع ذلك، يتطلب هذا التطبيق تقنيًا وسيطًا واحدًا فقط ، وهو array. يفرض باسكال شرطًا يقضي بأن تكون المصفوفات متجانسة. ويتم تجاوز هذا الشرط باستخدام سجل متغير. يُعرّف GNU Pascal مواصفات رسمية حقيقية للمعاملات المتغيرة باستخدام علامة الحذف ( ...)، ولكن حتى عام 2022 لم يتم تعريف آلية قابلة للنقل لاستخدامها. [ 16 ]

يسمح كل من GNU Pascal و FreePascal للوظائف المعلنة خارجيًا باستخدام مواصفات المعلمات الرسمية المتغيرة باستخدام علامة الحذف ( ...).

PHP

لا يهتم PHP بأنواع الوسائط المتغيرة إلا إذا تم تحديد نوع الوسيط.

دالة الجمع ( ... $nums ) : int { return array_sum ( $nums ); }echo sum ( 1 , 2 , 3 ); // 6

والوسائط المتغيرة المكتوبة:

دالة الجمع ( عدد صحيح ... $nums ) : عدد صحيح { إرجاع مجموع المصفوفة ( $nums }echo sum ( 1 , "a" , 3 ); // خطأ في النوع: يجب أن يكون الوسيط الثاني المُمرر إلى الدالة sum() من النوع int (منذ PHP 7.3)

بايثون

لا تهتم لغة بايثون بأنواع الوسائط المتغيرة.

من typing استورد Anydef foo ( a : Any , b : Any , * args : * tuple [ Any , ... ]) -> None : print ( args ) # args عبارة عن tuple (سلسلة غير قابلة للتغيير).إذا كان __name__ يساوي "__main__" : foo ( 1 , 2 ) # args = () foo ( 1 , 2 , 3 ) # arga = (3,) foo ( 1 , 2 , 3 , "hello" ) # args = (3, "hello")

يمكن تخزين الوسائط الرئيسية في قاموس.

من typing استورد Any و Unpackdef bar ( * args : * tuple [ Any , ... ], ** kwargs : Unpack [ dict [ str , Any ]]) -> Any : # جسم الدالة

لاحظ أنه على الرغم من أن argsله نوع *tuple[Any, ...]، *argsإلا أنه يتم أحيانًا وضع علامة عليه بـ typing.Any[ 17 ] .

راكو

في راكو ، تُعرف أنواع المعاملات التي تُنشئ الدوال المتغيرة باسم معاملات المصفوفة slurpy ، وهي مصنفة إلى ثلاث مجموعات:

مشروب سائل مسطح

يتم تعريف هذه المعلمات بعلامة نجمة واحدة ( *) وهي تعمل على تسطيح الوسائط عن طريق حل طبقة واحدة أو أكثر من العناصر التي يمكن تكرارها (أي، Iterables ).

sub foo ( $a , $b , * @args ) { say @args . perl ; } foo ( 1 , 2 ) # [] foo ( 1 , 2 , 3 ) # [3] foo ( 1 , 2 , 3 , "hello" ) # [3 "hello"] foo ( 1 , 2 , 3 , [ 4 , 5 ], [ 6 ]); # [3, 4, 5, 6]

مشروب سلوربي غير مسطح

يتم تعريف هذه المعلمات باستخدام علامتي نجمتين ( **)، وهي لا تقوم بتسوية أي وسائط قابلة للتكرار داخل القائمة، بل تحافظ على الوسائط كما هي تقريبًا:

sub bar ( $a , $b , ** @args ) { say @args . perl ; } bar ( 1 , 2 ); # [] bar ( 1 , 2 , 3 ); # [3] bar ( 1 , 2 , 3 , "hello" ); # [3 "hello"] bar ( 1 , 2 , 3 , [ 4 , 5 ], [ 6 ]); # [3, [4, 5], [6]]

مصّ سياقي

تُعرَّف هذه المعاملات بعلامة زائد ( ++)، وتُطبَّق عليها " قاعدة الوسيط الواحد " ، التي تُحدِّد كيفية التعامل مع وسيط slurpy بناءً على السياق. ببساطة، إذا تم تمرير وسيط واحد فقط وكان هذا الوسيط قابلاً للتكرار، فسيتم استخدامه لملء مصفوفة معاملات slurpy. في أي حالة أخرى، +@يعمل الأمر كما هو **@(أي، slurpy غير مُسطَّح).

sub zaz ( $a , $b , + @args ) { say @args . perl ; } zaz ( 1 , 2 ); # [] zaz ( 1 , 2 , 3 ); # [3] zaz ( 1 , 2 , 3 , "hello" ); # [3 "hello"] zaz ( 1 , 2 , [ 4 , 5 ]); # [4, 5]، وسيط واحد يملأ المصفوفة zaz ( 1 , 2 , 3 , [ 4 , 5 ]); # [3, [4, 5]]، يتصرف كـ **@ zaz ( 1 , 2 , 3 , [ 4 , 5 ], [ 6 ]); # [3, [4, 5], [6]]، يتصرف كـ **@

روبي

لا تهتم لغة روبي بأنواع الوسائط المتغيرة.

دالة foo ( * args ) طباعة args نهايةfoo ( 1 ) # يطبع `[1]=> nil`foo ( 1 , 2 ) # يطبع `[1, 2]=> nil`

الصدأ

لا تدعم لغة Rust الوسائط المتغيرة في الدوال. بدلاً من ذلك، تستخدم وحدات الماكرو التي تدعم الوسائط المتغيرة. [ 18 ] وهذا هو السبب الرئيسي في println!أن `format` عبارة عن ماكرو وليس دالة، حيث إنها تأخذ وسائط متغيرة للتنسيق.

macro_rules! calculate { // نمط `eval` واحد ( eval $e : expr ) => {{ { let val : usize = $e ; // فرض أن تكون الأنواع أعدادًا صحيحة println! ( "{} = {}" , stringify! { $e }, val ); } }};// تفكيك عدة عمليات `eval` بشكل متكرر ( eval $e : expr , $( eval $es : expr ), + ) => {{ calculate ! { eval $e } calculate ! { $( eval $es ), + } }}; }fn main () { calculate ! { \ eval 1 + 2 , eval 3 + 4 , eval ( 2 * 3 ) + 1 } }

يستطيع Rust التفاعل مع نظام الوسائط المتغيرة في لغة C عبر c_variadicمفتاح تبديل الميزات. وكما هو الحال مع واجهات C الأخرى، يُعتبر النظام جزءًا من Rust ، unsafeويُشار إليه برابط C. [ 19 ] يُشار إلى المعامل المتغير نفسه بـ ، ويمكن الإشارة إلى الدالة إذا كان من المضمون عدم وصولها إلى وسائطها المتغيرة. [ 20 ]...safe

#![feature(c_variadic)]دالة عامة غير آمنة خارجية "C" fn add ( n : usize , mut args : .. .) -> usize { let mut sum = 0 ; for _ in 0 .. n { sum += args . arg :: < usize > (); } sum }

سكالا

كائن البرنامج { // تخزن الدوال ذات الوسائط المتغيرة أي وسائط إضافية تستقبلها في مصفوفة. // وبالتالي، فإن `printArgs` هي في الواقع دالة ذات وسيط واحد: // مصفوفة متغيرة الطول من `String`. private def printArgs ( strings : String * ): Unit = { strings . foreach ( println ) }def main ( args : Array [ String ]): Unit = { printArgs ( "hello" ); // اختصار لـ printArgs(["hello"]) printArgs ( "hello" , "world" ); // اختصار لـ printArgs(["hello", "world"]) } }

سويفت

يهتم Swift بنوع الوسائط المتغيرة، ولكن النوع الشامل Anyمتاح.

func greet ( timeOfTheDay : String , names : String ...) { // هنا، names عبارة عن [String] print ( "يبدو أن لدينا \( names.count ) شخصًا" ) for name in names { print ( "مرحبًا \( name ) ، وقت \ ( timeOfTheDay ) جيد " ) } }تحية ( وقت اليوم : "صباح الخير" ، الأسماء : "جوزيف" ، "كلارا" ، "ويليام" ، "ماريا" )// الناتج: // يبدو أن لدينا 4 أشخاص // مرحباً جوزيف، صباح الخير // مرحباً كلارا، صباح الخير // مرحباً ويليام، صباح الخير // مرحباً ماريا، صباح الخير

تي سي إل

تكون دالة Tcl أو تعبير لامدا متغيرة الوسائط عندما يكون وسيطها الأخير argsعبارة عن قائمة (قد تكون فارغة) بجميع الوسائط المتبقية. هذا النمط شائع في العديد من الدوال الأخرى الشبيهة بالإجراءات. [ 21 ] [ 22 ]

proc greet { timeOfTheDay args } { puts "يبدو أن لدينا [llength $args] شخصًا"foreach name $args { puts "Hello $name, good $timeOfTheDay" } }تحية صباحية " جوزيف" "كلارا" "ويليام" "ماريا"الناتج: يبدو أن لدينا 4 أشخاص مرحباً جوزيف، صباح الخير مرحباً كلارا، صباح الخير مرحباً ويليام، صباح الخير مرحباً ماريا، صباح الخير

انظر أيضاً

ملحوظات

  1. كان جعل المعامل المُسمى اختياريًا ضروريًا لعدم وجود طريقة لتحديد دالة تأخذ عددًا غير محدد من الوسائط في C23 بعد إزالة تعريفات الدوال بنمط K&R. ولأن C++ كانت تستخدم هذا التركيب بالفعل لنفس الغرض، فقد كان هذا التغيير أيضًا وسيلة لزيادة التوافق بين اللغتين. [ 4 ]

مراجع

  1. كليمنس، بن (2014). لغة سي في القرن الحادي والعشرين: نصائح حول لغة سي من المدرسة الجديدة . دار نشر أورايلي ميديا، ص  224. ISBN 978-1491904442.
  2. CLP (H): برمجة المنطق المقيد للتحوطات
  3. "<cstdarg> (stdarg.h) - مرجع لغة C++" . www.cplusplus.com . مؤرشف من الأصل بتاريخ 31-10-2012 . تم الاطلاع عليه بتاريخ 02-10-2007 .
  4. "تم الانتهاء من C23: إليكم ما هو مدرج في القائمة §N2975 - تخفيف متطلبات قوائم المعلمات المتغيرة" . 31 يوليو 2022.
  5. جيلدينج، أليكس؛ مينيد، جانهيد (2022-04-15). "WG14-N2975 : تخفيف متطلبات قوائم المعلمات المتغيرة، الإصدار 3" (ملف PDF) . 
  6. "DCL50-CPP. لا تقم بتعريف دالة متغيرة على نمط لغة C" .
  7. cppreference.com. "std::same_as" . cppreference.com . cppreference.com . تم الاطلاع عليه بتاريخ 17 مايو 2026 .
  8. cppreference.com. "std::convertible_to" . cppreference.com . cppreference.com . تم الاطلاع عليه بتاريخ 17 مايو 2026 .
  9. مشروع لغة كاربون (1 أبريل 2026). "Variadics - توثيق لغة كاربون" . docs.carbon-lang.dev . مشروع لغة كاربون.
  10. "الوسائط الاختيارية" . إنتل . تم الاسترجاع في 18 مارس 2025 .
  11. "الاستعانة بالمثال: الدوال المتغيرة" .
  12. "دليل مرجع Lua 5.2" . www.lua.org . تم الاطلاع عليه بتاريخ 2023-02-05 .
  13. "دليل مرجع Lua 5.1" . www.lua.org . تم الاطلاع عليه بتاريخ 2023-02-05 .
  14. "المعلمات (دلفي)" . تم الاسترجاع في 28-08-2023 .
  15. "دليل مرجعي لبرنامج Free Pascal" . تم الاطلاع عليه بتاريخ 28-08-2023 .
  16. "دليل GNU Pascal" . تم الاطلاع عليه بتاريخ 28-08-2023 .
  17. "شرح *args و **kwargs - الكتابة الثابتة باستخدام بايثون" . typing.python.org . تم الاطلاع عليه بتاريخ 22-05-2026 .
  18. "المعاملات المتغيرة" . رست بالأمثلة .
  19. "2137-variadic" . كتاب Rust RFC .
  20. مطورو لغة Rust (25 يونيو 2026). "الكتل الخارجية" . docs.rust-lang.org . مطورو لغة Rust.
  21. "صفحة دليل الإجراء" . وثائق Tcl/Tk .
  22. "args" . ويكي تكلير .