多重ディスパッチ
多重ディスパッチとは、引数の型や数が違う同じ名前の関数を定義することができ、それが使用されるとき、引数の型や数によって適切なものが適用される仕組みのこと。
ひとつ前の記事で、Point 型に新しいコンストラクタを作って使ったのも多重ディスパッチの例だろう(たぶん)。
Point 型を例にして関数の多重ディスパッチを見てみよう。
まず、Point 型を定義する(まえの記事と同じ)。この型は内部に Int のフィールドを2つ持っている。
julia> Point(x) = Point(x, 0)
Point
julia> Point(3)
Point(3, 0)
そして、この Point 型を引数にとる distance 関数を定義する。この関数は2点のユークリッド距離を返す。次の通り。
julia> function distance(p1::Point, p2::Point)::Float64
sqrt((p1.x - p2.x)^2 + (p1.y - p2.y)^2)
end
distance (generic function with 1 method)
julia> distance(Point(0, 0), Point(3, 4))
5.0
さて、ここで新たに PointF 型を定義する。Pointと同様だけど、内部のフィールドが Float64 であるところが違う。
julia> struct PointF
x::Float64
y::Float64
end
この PointF の値を引数にして distance 関数を呼び出してみる。
julia> distance(PointF(0.0, 0.0), PointF(3.0, 4.0))
ERROR: MethodError: no method matching distance(::PointF, ::PointF)
The function `distance` exists, but no method is defined for this combination of argument types.
Closest candidates are:
distance(::Point, ::Point)
@ Main REPL[3]:1
Stacktrace:
[1] top-level scope
@ REPL[6]:1
このようにエラーになる。
そこで、PointF 型を引数にとる distance 関数(同じ名前であることに注目)を作る。
関数本体も同じで、違いは引数の型だけだ。
julia> function distance(p1::PointF, p2::PointF)::Float64
sqrt((p1.x - p2.x)^2 + (p1.y - p2.y)^2)
end
distance (generic function with 2 methods)
そして使ってみる。
julia> distance(PointF(0.0, 0.0), PointF(3.0, 4.0))
5.0
このようにうまく機能する。これが多重ディスパッチ。
2つめの distance 関数を定義したところに、distance (generic function with 2 methods) と表示されている。この 2 methods が、2つのバリエーションがあることを示しているらしい(そしてどうやら「メソッド」と呼ぶらしい)。
