パラメトリック型
パラメトリック型とは、他の言語でジェネリクスとかテンプレートとか呼ばれている機能と似たものだ。 次のように定義する。
julia> struct Point{T}
x::T
y::T
end
T を型パラメータと呼び、Point{T} は「T をパラメータとする Point 型」といえる。
T はインスタンスを生成するときに、具体型の Int とか Float64 とかに決まる。
julia> p = Point(2, 3)
Point{Int64}(2, 3)
julia> q = Point(2.2, 3.7)
Point{Float64}(2.2, 3.7)
または、p = Point{Int}(2, 3) のように型を指定してもいい。
昨日の記事で、フィールドの型ごとに Point と PointF に分けていた複合型を Point{T} ひとつにできるわけだ。
関数も型パラメータをとるように書ける。
原点からの距離を計算する distance 関数を定義してみよう。
julia> function distance(p::Point{T}) where T
sqrt(p.x^2 + p.y^2)
end
distance (generic function with 1 method)
引数の型に Point{T} を指定するだけでなく、後ろに where T とつける必要がある。ちゃんと動作するか試してみる。
julia> p
Point{Int64}(2, 3)
julia> distance(p)
3.605551275463989
julia> q
Point{Float64}(2.2, 3.7)
julia> distance(q)
4.304648650006177
もし、Point{Int} と Point{Float64} で関数本体部分を異なる実装にしたいときには、多重ディスパッチをつかう。
function distance(p::Point{Int})
# Int の時の実装
end
function distance(p::Point{Float64})
# Float64の時の実装
end
さて、2点間の距離を計算する distance2 関数(昨日の記事で書いた distance)を書いてみよう。上の p と q を引数にとれるようにするには、型パラメータを2つにする必要がある。なぜなら p と q では型が違うから。次のようにする。
julia> function distance2(p1::Point{T}, p2::Point{U}) where {T,U}
sqrt((p1.x - p2.x)^2 + (p1.y - p2.y)^2)
end
distance2 (generic function with 1 method)
型パラメータが2つ(以上)ある場合には where {T,U} のように、{ } をつける。
また、ここでは型パラメータに T と U を使っているけど、これは決まった文字があるわけではないので T1 と T2 とかでも構わない。
では試してみよう。
julia> p
Point{Int64}(2, 3)
julia> q
Point{Float64}(2.2, 3.7)
julia> distance2(p, q)
0.728010988928052
p と q を逆にしてもちゃんと動作する。
julia> distance2(q, p)
0.728010988928052
