قدّم مفهوم Basics طريقتين لتعريف دالة.
في الصورة الأكثر عمومية، الصيغة متعددة الأسطر:
function muladd(x, y, z)
x * y + z
end
وصيغة "الإسناد" أو "السطر الواحد" للتعريفات القصيرة:
muladd(x, y, z) = x * y + z
وفي صيغة ثالثة أقصر من ذلك، يمكن إنشاء دالة قصيرة تُستخدم مرة واحدة دون اسم:
julia> map(x -> 2x, 1:3)
4-element Vector{Int64}:
2
4
6
julia> map((x, y) -> x * y, 1:3, 4:6)
3-element Vector{Int64}:
4
10
18
في هذه الحالة، x -> 2x هي "دالة مجهولة". وهي تكافئ ما تسميه بعض اللغات الأخرى "دالة لامدا".
لاحظ أن تعدد الوسائط يتطلب أقواسًا، كما في (x, y) -> x * y.
الدوال المجهولة شائعة في كود Julia، لا سيما عند دمجها مع الدوال من الرتبة الأعلى مثل map() وfilter().
حتى الآن في المنهج، لم ننظر إلا إلى دوال لها عدد محدد من الوسائط، وتتطلب أن يوفّر استدعاء الدالة جميع هذه الوسائط بالترتيب الصحيح. سيكون هذا مقيّدًا وغير مريح، لذا توجد خيارات أخرى عديدة.
مثل لغات كثيرة، تسمح تعريفات الدوال في Julia بتحديد قيم افتراضية لوسائط فردية.
ويمكن بعد ذلك لاستدعاء الدالة إما أن يوفّر قيمة لهذا الوسيط، وإما أن يحذفه ويعتمد على القيمة الافتراضية.
julia> f(x, y=10) = x * y
f (generic function with 2 methods)
julia> f(2, 3)
6
julia> f(2)
20
يجب أن تأتي جميع الوسائط بدون قيم افتراضية قبل أي وسائط مع قيم افتراضية، ما يعني أن f(x=2, y) ستكون غير صالحة.
تستخدم جميع الأمثلة حتى الآن positional arguments، حيث يجب أن تطابق القيم الموفَّرة في استدعاء الدالة ترتيب الوسائط المقابلة في تعريف الدالة.
وكما في لغات كثيرة، تسمح Julia أيضًا بـkeyword arguments.
ويجب أن يحدّد استدعاء الدالة اسم الوسيط، لكن يمكن بعد ذلك تحديد عدة وسائط مفتاحية بأي ترتيب.
من السمات المميزة لـJulia أن الوسائط المفتاحية (إن وُجدت) في تعريف الدالة يجب أن تسبقها فاصلة منقوطة ; تفصلها عن أي وسائط موضعية.
ويمكن لاستدعاء الدالة أن يستخدم ; أو , بين آخر وسيط موضعي وأول وسيط مفتاحي.
julia> b(x; y) = x + y
b (generic function with 1 method)
julia> b(2, y=3)
5
# keyword is required when calling
julia> b(2, 3)
ERROR: MethodError: no method matching b(::Int64, ::Int64)
The function `b` exists, but no method is defined for this combination of argument types.
ويمكن اختياريًا تحديد قيم افتراضية، تمامًا كما هو الحال في الوسائط الموضعية.
من الشائع أن ينتهي بك الأمر إلى صياغة مثل myarg=myarg داخل استدعاء دالة، عندما يكون متغير بالاسم نفسه الذي يحمله المعامل قد حُسب مسبقًا.
وتُسمح صيغة مختصرة في هذه الحالة:
julia> width = 4.0
4.0
julia> height = √ width
2.0
julia> area(; width, height) = width * height
area (generic function with 1 method)
# repetition
julia> area(; width=width, height=height)
8.0
# shorthand form
julia> area(; width, height)
8.0
splat وslurp
هذان هما الاسمان المعتادان لجانب مفيد من صياغة Julia، إن كنت تتساءل.
وكلاهما يشير إلى العامل ....
splatيُستخدم splat في استدعاءات الدوال، لتوسيع المجموعات إلى قيم فردية تحتاجها الدالة.
وربما يكون العرض أسهل من الشرح:
julia> fxyz(x, y, z) = x * y * z
fxyz (generic function with 1 method)
julia> xyz = [2, 3, 4]
3-element Vector{Int64}:
2
3
4
# Using the vector directly in a function call is invalid
julia> fxyz(xyz)
ERROR: MethodError: no method matching fxyz(::Vector{Int64})
The function `fxyz` exists, but no method is defined for this combination of argument types.
# splatting converts the vector to 3 numbers, used as positional arguments
julia> fxyz(xyz...)
24
بعض "استدعاءات الدوال" مخفية بفعل السكر النحوي، لذا يمكن استخدام splat أيضًا بطرق أقل وضوحًا.
على سبيل المثال، يستخدم الإسناد المتعدد داخليًا دالة إنشاء الصف:
julia> first, rest... = [1, 2, 3, 4]
4-element Vector{Int64}:
1
2
3
4
julia> first
1
julia> rest
3-element Vector{Int64}:
2
3
4
يمكن أيضًا توفير الوسائط المفتاحية باستخدام splat، وذلك عادةً عبر named tuple.
ويعمل Dict أيضًا، لكن يجب أن تكون المفاتيح رموزًا (لن تعمل السلاسل النصية هنا).
# function with 3 keyword arguments
julia> fabc(; a, b, c) = a + b + c
fabc (generic function with 1 method)
# named tuple
julia> abc_nt = (a=2, b=3, c=4)
(a = 2, b = 3, c = 4)
# there are no positional arguments, so need to use ; before kw argument
julia> fabc(;abc_nt...)
9
# Dict
julia> abc_dict = Dict(:a=>2, :b=>3, :c=>4)
Dict{Symbol, Int64} with 3 entries:
:a => 2
:b => 3
:c => 4
julia> fabc(;abc_dict...)
9
slurpيُستخدم slurp في تعريف الدالة، لحزم أي عدد من القيم الفردية في مجموعة.
julia> f_more(i, j, more...) = i + j + sum(more)
f_more (generic function with 1 method)
julia> f_more(1, 3, 5, 7, 9, 11)
36
اسم الوسيط الذي يجمعه slurp (وهو هنا more) ليس ذا أهمية.
ويختار المترجم نوع هذا المتغير، لكنه في حالة الوسائط الموضعية يكون على الأرجح tuple أو ما يشبهه.
يمكن أيضًا استخدام slurp مع الوسائط المفتاحية، فينتج Dict (أو ما يشبهه).
julia> f_kwslurp(x, y; switches...) = :mult in keys(switches) ? x * y : x + y
f_kwslurp (generic function with 1 method)
julia> f_kwslurp(5, 6; mult=true)
30
julia> f_kwslurp(5, 6)
11
يمكن استخدام أي وسائط مفتاحية في الاستدعاء. ويعود الأمر إلى تعريف الدالة في تحديد الكلمات المفتاحية التي يستجيب لها وتلك التي يتجاهلها.