最一般來說,多行形式:
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是一個「匿名函式」。
這等同於其他語言所稱的「lambda 函式」。
請注意,多個引數需要括號,例如(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
這些是 Julia 語法中某個實用層面的標準名稱,以防你好奇。
兩者都指...運算子。
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 用於函式_定義_,將任意數量的個別值打包到集合中。
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
呼叫時可以使用任何關鍵字引數。 函式定義要決定要回應哪些關鍵字,以及忽略哪些。