A Basics fogalom kétféle módszert mutatott be egy függvény definiálására.
A legáltalánosabb a többsoros forma:
function muladd(x, y, z)
x * y + z
end
Az „értékadásos”, másként „egysoros” forma rövid definíciókhoz:
muladd(x, y, z) = x * y + z
Egy harmadik, még rövidebb formában létrehozhatunk egy rövid, egyszer használatos függvényt név nélkül is:
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
Ebben az esetben az x -> 2x egy „névtelen függvény”.
Ez megegyezik azzal, amit néhány más nyelv „lambda-függvénynek” nevez.
Figyeld meg, hogy több argumentum esetén zárójelek kellenek, mint például a (x, y) -> x * y esetében.
A névtelen függvények gyakoriak a Julia-kódban, különösen akkor, ha olyan magasabb rendű függvényekkel kombináljuk őket, mint a map() és a filter().
A tantervben eddig csak olyan függvényekkel találkoztunk, amelyeknek pontosan meghatározott számú argumentuma van, és a hívásukhoz mindegyiket meg kell adni a helyes sorrendben. Ez túl korlátozó és kényelmetlen lenne, ezért több más lehetőség is van.
Sok más nyelvhez hasonlóan a Julia is lehetővé teszi, hogy a függvénydefinícióban alapértelmezett értéket adjunk meg az egyes argumentumokhoz.
A függvényhívás ekkor vagy megadja az argumentum értékét, vagy elhagyja, és az alapértelmezett értékre támaszkodik.
julia> f(x, y=10) = x * y
f (generic function with 2 methods)
julia> f(2, 3)
6
julia> f(2)
20
Minden alapértelmezés nélküli argumentumnak meg kell előznie az alapértelmezéssel rendelkező argumentumokat, vagyis az f(x=2, y) érvénytelen lenne.
Az eddigi példák mind positional arguments-t használnak, ahol a függvényhívásban megadott értékek sorrendjének meg kell egyeznie a függvénydefinícióban szereplő megfelelő argumentumok sorrendjével.
Sok más nyelvhez hasonlóan a Julia is támogatja a keyword arguments használatát.
A függvényhívásban meg kell adni az argumentum nevét, de több kulcsszóargumentum ezután tetszőleges sorrendben megadható.
A Julia különlegessége, hogy a függvénydefinícióban a kulcsszóargumentumok (ha vannak) elé pontosvesszőt ; kell tenni, hogy elválasszuk őket a pozicionális argumentumoktól.
A függvényhívásban az utolsó pozicionális argumentum és az első kulcsszóargumentum között a ; és a , közül bármelyiket használhatjuk.
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.
Alapértelmezett értékeket opcionálisan megadhatunk, pontosan úgy, mint a pozicionális argumentumoknál.
Gyakori, hogy egy függvényhívásban myarg=myarg formájú szintaxissal találkozunk, amikor egy, a paraméterrel azonos nevű változót már korábban kiszámoltunk.
Ilyenkor rövidített szintaxis is használható:
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
Ezek a szokásos elnevezései a Julia szintaxis egy hasznos részének, ha esetleg elgondolkodtál volna rajta.
Mindkettő a ... operátorra utal.
A splatolás függvény_hívásokban_ használatos, hogy egy gyűjteményt egyedi értékekké bontson szét, amelyeket a függvény megkövetel.
Ezt könnyebb bemutatni, mint elmagyarázni:
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
Némely „függvényhívás” szintaktikai cukorka mögé rejtőzik, így a splatolás kevésbé nyilvánvaló módokon is használható.
Például a többszörös értékadás a háttérben egy tuple-konstruktor függvényt használ:
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
Kulcsszóargumentumokat is megadhatunk splatolással, jellemzően egy named tuple használatával.
Egy Dict is működik, de a kulcsoknak szimbólumoknak kell lenniük (itt a stringek nem működnek).
# 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
A slurpolás a függvény_definícióban_ használatos, hogy tetszőleges számú egyedi értéket csomagoljon egy gyűjteménybe.
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
A slurpolt argumentum neve (ebben az esetben more) nem lényeges.
A változó típusát a fordító választja ki, de pozicionális argumentumok esetén valószínűleg tuple vagy valami hasonló lesz.
A kulcsszóargumentumok is slurpolhatók, ekkor egy Dict-et (vagy hasonlót) kapunk.
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
A hívásban bármilyen kulcsszóargumentum használható. A függvénydefiníció dönti el, hogy mely kulcsszavakra reagál, és melyeket hagy figyelmen kívül.