Bye Bye Moore

PoCソルジャーな零細事業主が作業メモを残すブログ

【自習メモ】Rust言語のstruct、trait、deriveについて

実際のところ

structとtrait

乱暴にまとめると、structがデータ構造を定義し、traitが振る舞いを定義するときに使うもの

// データ構造を表現するstruct
// 構造はprivateなもので、ユーザーは意識しないで済む
struct User {
    name: String,
    email: String,
    age: u8,
}

// 振る舞いを定義するtrait
// インターフェイスをpublicに提供
// 可変サイズとして扱われるのでヒープ領域にて定義(Box)
trait UserBehavior {
    fn login(&self) -> bool;
    fn update_profile(&mut self) -> Result<(), Box<dyn Error>>;
}

で、implキーワードでstructとtraitを紐付け

// とりあえず振る舞いの実験なので常に正常系で……
use std::error::Error;
impl UserBehavior for User {
   fn login(&self) -> bool {
       true  // 常にログイン成功
   }

   // Errorはヒープ領域へのスマートポインタであるBoxを介して活用
   // Boxの働きによって、メモリの確保と開放は自動的に管理される
   fn update_profile(&mut self) -> Result<(), Box<dyn Error>> {
       Ok(())  // 常に成功
   }
}

derive属性

structやenumに追加の振る舞いを教え込むマクロを実行してくれるやつ……
自動でtraitの振る舞いをぶっ込んでくれる機能という事

#[derive(Debug)]
struct User {
    name: String,
    email: String,
    age: u8,
}

とやると、デバッグ用機能を勝手に読み出してくれるようになります。
具体的には、

fn main() {
    // ユーザーの定義。
    // "mut"で変更可能にしとかないとTraitの挙動が意味を為さない
    let mut user = User {
        name: String::from("Alice"),
        email: String::from("alice@example.com"),
        age: 30,
    };

    // #[derive(Debug)]の霊験で":?"キーワードでデバッグ情報がでてくるようになる
    println!("User: {:?}", user);
}
Builderパターン

少し古い例だと、Builderパターンという手法もあった様子。
ただ、可読性やエラー処理の一貫性から今はderive属性が好まれているとのこと。