W.I.S. Laboratory
menu-bar

Rust


Rustでコンストラクタ

Rustは仕様上コンストラクタを持っていない。
Dropトレイトでデストラクタは実現できる(スマートポインタを実現するためにどうしても必要だったのだろうと思う)が、コンストラクタは無い。
そうはいっても普段C++などを書いてる人間にとっては欲しくなるときがある。
それにインスタンス生成のたびに全フィールドの初期化コードをその場にズラズラ書きたくないわけで・・私が古い人間なんだろうけども。
Go言語だとインスタンスを生成していないと構造体に紐付いた関数を呼び出すことができないので、慣例的に「New」+「構造体名」という普通の関数を作ってその関数内でインスタンスを生成し、そのポインタを返すという力技でコンストラクタ代わりにするんだけど、Rustの場合はインスタンスを生成しなくても構造体にインプリメンテーションしたメソッドを呼び出せるので少しキレイに書ける。
とはいっても、ここでインプリメンテーションしているnew()はコンストラクタではなく、ただそういう名前を付けた関数であり、この関数内でインスタンスを生成しているに過ぎない。
この関数名は別に「hoge()」でも「piyo()」でも問題ないが、「new()」という関数名になったのはRust自身がそういう名前を使っているので皆がそれに倣ったからだろうと思う。
「new」というとヒープ上に生成されるようなイメージだが、RustはBox化しない限りスタックに置かれる。
こうしてみると、スコープアウト時に呼び出されるデストラクタは言語仕様に強く依存するが、コンストラクタはなんとでもなるという感じがする。

フィールドの値を変更したいときは new() からインスタンスを受け取る変数だけに mut を付ければ良い。

スタックではなく、ヒープにインスタンスを生成したい時はBox化すれば可能。
上の2つの例ではnew()関数はインスタンスそのものを返しているが、Box化するとインスタンスへのポインタを返すことになる。
なので正しくはフィールドにアクセスする際に「(*f).val1」としてデリファレンスしないといけないはずだが、「f.val1」でもアクセスできる。
CやC++ならコンパイルエラーになるところだが、Rustはそのへん寛容らしい。
ただしRustはオブジェクト指向型言語ではないので、メソッドはインスタンスに含まれていない。(インプリメンテーションで構造体と関数が紐付いているだけ)
なので、Box化した場合でもメソッド呼び出しは「f.get_sum()」が正しい。(デリファレンスしようとすると cannot be dereferenced エラーになる)
ちなみにこれは「構造体Fooに紐付いたget_sum()関数の第一引数にインスタンスfを借用渡しで投げる」という意味なので、「Foo::get_sum(&f)」と書いても同じ動作になる。


[ 戻る ]
saluteweb