4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Rust の Default::default(), T::new(), T::from() の使い分け

Posted at

概要

Rustのnew()を複数定義することができないため、new()の使いどころは悩みますね。

リストやツリーなど自己参照型の構造体を書いていて、こうしたら良いのでは?というパターンが見えてきたので、まとめます。

ポイント

  • new は構造体のすべてのフィールドを明示的に初期化するメソッドとして実装する
    • 全フィールドを初期化するメソッドが増減することはないから、new()と同名のものを複数定義せずに済む
    • 全フィールドが必須なら、newだけあればよい
  • 引数の指定が必要なかったり、すべて省略できる場合は Defaultトレイトを使う
  • データのみを指定して初期化する場合は Fromトレイトが役立つ
    一部フィールドを初期化する場合に役立つ場合もある
  • どれにも当てはまらなければ、専用の初期化メソッドを作る
    • 決まった使い方しかなければ、分かりやすい名前の初期化メソッドを作ればよい
    • パラメーターが多くあるなら、デザインパターンのBuildパターンを適用すればよい

例: Default

初期化でパラメーターが不要なら、 Defaultトレイトを使う。
これにより、個々の new() の仕様について学習せずに使える。

let mut list: SList<u8> = Default::default();
list.push_front(1);
list.push_front(2);
pub enum SList<T> {
    Cons(T, Rc<SList<T>>),
    Nil,
}

impl<T> Default for SList<T> {
    fn default() -> Self { SList::Nil }
}

例: From と new

  • new はすべてのフィールドを明示的に初期化するためのメソッドとして定義するのが良い
    • new の効用として、内部の構造を隠ぺいできるメリットがある
      例えば、Rc::new(…) を Box::new(…) に変更した場合に修正の影響が少なくできる
  • from はデータのみ指定して、それ以外をデフォルトとする場合に都合が良い
    newは1つしか宣言できないので、それを補う役割ができる。
pub enum SList<T> {
    Cons(T, Rc<SList<T>>),
    Nil,
}

impl<T> SList<T> {
    pub fn new(v: T, next: SList<T>) -> Self {
        SList::Cons(v, Rc::new(next))
    }

    pub fn push_back(&mut self, v: T) {
        let mut cur_slist_ref_mut = self;

        while let SList::Cons(_, next_rc_ref_mut) = cur_slist_ref_mut {
            // &mut SList<T> <- &mut Rc<SList<T>>
            cur_slist_ref_mut = Rc::get_mut(next_rc_ref_mut).unwrap();
        }

        let _ = std::mem::replace(cur_slist_ref_mut, SList::from(v));
    }

    pub fn push_front(&mut self, v: T) {
        let head_node: SList<T>;
        head_node = std::mem::replace(self, SList::Nil);

        let _ = std::mem::replace(self, SList::new(v, head_node));
    }
}

impl<T> From<T> for SList<T> {
    fn from(v: T) -> Self { SList::new(v, SList::Nil) }
}
4
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
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?