問題の背景
Rustにはオブジェクト指向言語における従来のコンストラクタはありませんが、初期化を明示的に行う設計パターンを実装するための関連関数(最も一般的にはnew)があります。関連関数は、構造体のインスタンスを事前に設定された値で作成したり、メモリを予約するなどの追加のロジックを持たせたりすることができます。
問題点
多くの人がnewのみを使用し、他のファクトリメソッドパターン(たとえば、with_capacity)を忘れたり、構造体の初期化を誤って実装したり(特にプライベート/パブリックフィールドに関して)、不変条件のエラーを引き起こすことがあります。
解決策
newタイプの関連関数はimplを介して実装され、不変条件を持つオブジェクトを作成するための唯一のエントリーポイントになる可能性があります。with_capacityのような関数は、メモリを事前に割り当てるなどの追加機能を提供します。
次にコード例を示します:
pub struct MyBuffer { data: Vec<u8>, } impl MyBuffer { pub fn new() -> Self { MyBuffer { data: Vec::new() } } pub fn with_capacity(cap: usize) -> Self { MyBuffer { data: Vec::with_capacity(cap) } } }
主な特徴:
newを実装しないと、Rustは自動的にそれを作成しますか?
いいえ。newの自動生成はありません。メソッドが明示的に実装されていなければ、それは存在しません。たとえ構造体がすべてのフィールドがパブリックであってもです。
newとDefaultの違いは何ですか?
Defaultはトレイトコンストラクタであり、型がDefaultを実装または明示的に継承している場合のみ呼び出すことができます。一般的なアルゴリズムに標準的ですが、必ずしもnewと一致するわけではありません。
プライベート構造体に対してnewおよびwith_capacityメソッドを使用できますか?
はい、メソッドはパブリックまたはプライベートにすることができますが、プライベート構造体のためにパブリックコンストラクタを作成しても、ユーザーがモジュールの外でその構造体のインスタンスを作成することはできません。
不変条件のないオープン構造体で、すべてのフィールドがパブリック:
pub struct User { pub login: String, pub active: bool }
利点:
欠点:
フィールドがプライベートで、newを介してのみ作成され、不変条件が確保されている:
pub struct User { login: String, active: bool } impl User { pub fn new(login: String) -> User { User { login, active: true } } }
利点:
欠点: