LoginSignup
0
3

More than 1 year has passed since last update.

Juliaの構造体の分解と合成

Last updated at Posted at 2023-03-15

構造体の分解

構造体を分解するには、構造体名の取得、各フィールド名の取得、各フィールドの取得が必要。

構造体名は、typeofで取得できる。

julia> struct A
           x
           y
       end

julia> a = A(1,2)
A(1, 2)

julia> println(typeof(a))
A

フィールド名はfieldnames で取得。

julia> fieldnames(A)
(:x, :y)

各フィールドの値はgetproperty で取得。

julia> getproperty(a, :x)
1

まとめると以下の関数で分解することができる。

# returns type and vals
function decompose(target)
    t = typeof(target)
    vals = [getproperty(target, name) for name in fieldnames(t)]
    t, vals
end 

構造体の合成

構造体の合成はコンストラクタを使えばできるように思える。

t(vals...)

しかしこれは、コンストラクタが明示的に実装されているとうまく行かない。

julia> struct B 
         x
         y
         B(x) = new(x, 1)
       end

julia> b = B(1)
B(1, 1)

julia> t, vals = decompose(b)
(B, [1, 1])

julia> t(vals...)
ERROR: MethodError: no method matching B(::Int64, ::Int64)
Closest candidates are:
  B(::Any) at REPL[21]:4

明示的に1引数のコンストラクタが作られたので、デフォルトの2引数のコンストラクタが見えなくなっている。

これを回避する方法を探したらこんな方法を見つけた。

@generated function __new__(T, args...)
    return Expr(:splatnew, :T, :args)
end

function compose(t, vals)
    __new__(t, vals...)
end

正直言ってなんでこれでうまくいくのか完全に腹落ちしていないのだが、
これだとうまくいく。

julia> compose(t, vals)
B(1, 1)

なおこの方法だと、引数の数が間違っていた場合に、エラーも出さずに失敗するので要注意。

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3