関数とは、タプルを入力とし、値を返すオブジェクトです。
オブジェクトなので、関数そのものを代入したり、それを利用して関数を呼び出したりすることもできます。
julia> add(x,y) = x + y
add (generic function with 1 method)
julia> f = add
add (generic function with 1 method)
julia> f(5,7)
12
関数の引数は共有渡し(pass-by-sharing)によって渡されます。文字通り値が共有され、関数呼び出し時に値は関数へコピーされません。値が格納されている場所のようなもの(bindings)が渡されます。その意味では C/C++言語におけるポインタ渡しと類似していますが、Julia にはポインタという概念はなく、また、振る舞いも少し違います。
引数が配列のように mutable(可変)なオブジェクトの場合、関数内における変更は関数の呼び出し元にも反映されます。一方、数値や文字列といった immutable(不変)なオブジェクトの場合、関数内での変更は呼び出し元には反映されません。
引数の型は ::型
という構文で指定できます。
以下は階乗(n!
)を求める例です。
julia> factorial(n::Integer) = n <= 1 ? one(n) : n * factorial(n-1)
factorial (generic function with 1 method)
julia> factorial(5)
5
型を指定する意義は、それぞれの型で関数の処理を変えたい場合、その型以外の入力では戻り値に意味がない場合、などに限られます。型を指定することによる効率化も通常は期待できません。柔軟性を保つためにも、型を制約しすぎることは推奨されていません。
TODO...
TODO...
TODO...
デフォルトでは、関数の最後に評価された値が関数の戻り値となります。return
を使うと、任意のタイミングで関数を終了し、戻り値を返すことができます。
何も値を戻したくない場合は、nothing
を使います。
julia> function test()
println("test")
return nothing
end
test (generic function with 1 method)
nothing
は省略可能で、return
だけでも同じ意味になります。逆に、関数の最後に評価された値が戻り値になることから、nothing
だけでも同じ意味になります。
あまり必要な場面は多くなさそうですが、::
を用いて、戻り値の型を指定することも可能です。
julia> function add(n)::Integer
return x + y
end
add (generic function with 2 methods)
戻り値としてタプルを指定することもできます。このように、複数の値を返すことは容易です。
julia> function test(x)
return x^2, sqrt(x)
end
test (generic function with 2 methods)
julia> x, y = test(2.0)
(4.0, 1.4142135623730951)
julia> _, y = test(2.0)
(4.0, 1.4142135623730951)
julia> y
1.4142135623730951
名前のない関数、いわゆる無名関数(anonymous function)を定義することもできます。
julia> x -> x - 273.15
#1 (generic function with 1 method)
julia> (x, y) -> x + 2y - 1
#3 (generic function with 1 method)
この例のように、引数が1個しかない場合は左辺の括弧を省略できます。ちなみに #1 は、コンパイラが内部的につけている関数名です。
無名関数は、function
文において関数名を省略することでも定義できます。
julia> function (x)
x - 273.15
end
#1 (generic function with 1 method)
無名関数の利用場面としては、関数への引数として関数を渡す状況(コールバック)が考えられます。コールバックによって関数の汎用性が高まるとともに、無名関数を指定することで名前の無用な重複を気にする必要がなくなります。
julia> function calc4( f, v )
f(v)^4
end
calc2(x -> x + 273.15, 10)
80173.92249999999
もう少し実用的な例としては、map()
関数における活用例があります。map()
は関数と引数配列を与えると、戻り値を配列で返す関数です。
julia> map( x -> x + 273.15, [10.0, 15.5, 22.3] )
3-element Vector{Float64}:
283.15
288.65
295.45