Juliaのgetpropertyが面白い
Juliaの標準パッケージの中身を見ていると実装がなかなか面白くて勉強になる.今回getpropertyという面白いものを知ったので共有します.
Base.getpropertyとは
[構造体].[フィールド名]と実行したら呼ばれる関数で,デフォルトでは構造体のインスタンスのフィールドの値が戻ってきます.
struct Hoge x end h = Hoge(3)
xには3が入っているのでこのように動作しますね.
julia> h.x
3
では存在しないフィールド名を使うとどうなるでしょうか
julia> h.type ERROR: type Hoge has no field type Stacktrace: [1] getproperty(::Any, ::Symbol) at ./sysimg.jl:18
当然エラーがでますね.しかしエラーに注目してください,getproperty
という関数が呼ばれています.第一引数が構造体のインスタンスでこの例の場合h
です.第二引数がSymbol
でこの例の場合type
です.
これを定義することでJuliaの多重ディスパッチにより定義したgetproperty
が実行されて存在しないフィールドにアクセスできるかのような動作を実現できます.
Base.getpropertyを定義する
存在するh.x
でx
の値を返して,h.type
でh
の型名を返してみる.なお,typeof
関数があるのでこの実装には無駄ですが一例としてこのような実装をしてみます.
struct Hoge x end function Base.getproperty(H::Hoge, d::Symbol) # H.typeのときはHの型であるHogeを返す d == :type && return typeof(H) # その他の場合そのままフィールドの値を返す return getfield(H, d) end
例
julia> h = Hoge(3) Hoge(3) julia> h.x 3 julia> h.type Hoge
こんな感じに動作します.supertype
が同じ複数のstruct
を定義して似たような動作をさせたいけどそれぞれのフィールド変数が大きく異なる場合などに便利かもしれない.
Julia REPLで候補としてでてくるようにする
このままではREPLでTAB補間しようとしたときにHogeのフィールドネームとしてtype
が現れません.
現れるようにするのも簡単で,Base.propertynames
を定義すればOK.
function Base.propertynames(H::Hoge, private::Bool=false) return (:type, fieldnames(Hoge)...) end
TAB補間しようとするとtypeも候補として出てくる.
julia> h.
type x