kdnakt blog

hello there.

Rust dojo第52回を開催した

一週空いて第52回です。前回はこちら。

kdnakt.hatenablog.com

 

 

[第52回の様子]

2022/08/31に第52回を開催した。

 

内容としてはRust By Example 日本語版の16. トレイトの続きで、「16.8. Supertraits」に取り組んだ。

ただの親トレイトの話かと思ったら意外と勉強になる内容だった。

 

参加者は自分を入れて確か5人。今週も安定して参加者がいて助かる。

 

[学んだこと]

  • 16.8. Supertraits
  • RustではJavaのような継承はできないが、あるトレイトを別のトレイトのあるトレイトの上位集合として定義できる
  • PersonトレイトとStudentトレイトを例にとると次のような感じ
trait Person {
    fn name(&self) -> String;
}

// PersonがStudentの上位集合となる
// Studentトレイトを実装する場合、Personトレイトも別途実装する必要がある
trait Student: Person {
    fn university(&self) -> String;
}
  • 複数のトレイトを上位集合とすることもできる
trait Programmer {
    fn fav_language(&self) -> String;
}

// CompSciStudentはProgrammerとStudentをそれぞれ上位集合としてもつ
trait CompSciStudent: Programmer + Student {
    fn git_username(&self) -> String;
}

// &dyn CompSciStudent型に対して、上位集合のメソッドを呼び出すことができる
fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String {
    format!(
        "My name is {} and I attend {}. My favorite language is {}. My Git username is {}",
        student.name(), // Personトレイトのメソッド
        student.university(), // Studentトレイトのメソッド
        student.fav_language(), // Programmerトレイトのメソッド
        student.git_username() // CompSciStudentトレイトのメソッド
    )
}
  • テキスト本文では、CompSciStudent型を実装した構造体が用意されていなかったので、実際に実装してみることにした。
  • まずはそれぞれの関数で返す値を保持した構造体を用意する
// 順番に、name, university, fav_language, git_usernameのつもり
struct CompSciStudentImpl(String, String, String, String);
  • 次に、CompSciStudentトレイトを実装し、main()関数でcomp_sci_student_greeting()を呼び出す
impl CompSciStudent for CompSciStudentImpl {
    fn name(&self) -> String { self.0.to_string() }
    fn university(&self) -> String { self.1.to_string() }
    fn fav_language(&self) -> String { self.2.to_string() }
    fn git_username(&self) -> String { self.3.to_string() }
}


fn main() {
    let john = CompSciStudentImpl(
        "John Doe".to_string(),
        "test".to_string(),
        "Rust".to_string(),
        "j_doe".to_string()
    );
    let greet = comp_sci_student_greeting(&john);
    println!("{greet}");
}
  • しかし、これは大量のコンパイルエラーとなってしまった。
// 以下のコンパイルエラー
error[E0407]: method `name` is not a member of trait `CompSciStudent`
  --> src/main.rs:24:5
   |
24 |     fn name(&self) -> String { self.0.to_string() }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `CompSciStudent`

error[E0407]: method `university` is not a member of trait `CompSciStudent`
  --> src/main.rs:25:5
   |
25 |     fn university(&self) -> String { self.1.to_string() }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `CompSciStudent`

error[E0407]: method `fav_language` is not a member of trait `CompSciStudent`
  --> src/main.rs:26:5
   |
26 |     fn fav_language(&self) -> String { self.2.to_string() }
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `CompSciStudent`

error[E0277]: the trait bound `CompSciStudentImpl: Student` is not satisfied
  --> src/main.rs:23:6
   |
23 | impl CompSciStudent for CompSciStudentImpl {
   |      ^^^^^^^^^^^^^^ the trait `Student` is not implemented for `CompSciStudentImpl`
   |
note: required by a bound in `CompSciStudent`
  --> src/main.rs:17:36
   |
17 | trait CompSciStudent: Programmer + Student {
   |                                    ^^^^^^^ required by this bound in `CompSciStudent`

error[E0277]: the trait bound `CompSciStudentImpl: Programmer` is not satisfied
  --> src/main.rs:23:6
   |
23 | impl CompSciStudent for CompSciStudentImpl {
   |      ^^^^^^^^^^^^^^ the trait `Programmer` is not implemented for `CompSciStudentImpl`
   |
note: required by a bound in `CompSciStudent`
  --> src/main.rs:17:23
   |
17 | trait CompSciStudent: Programmer + Student {
   |                       ^^^^^^^^^^ required by this bound in `CompSciStudent`

Some errors have detailed explanations: E0277, E0407.
  • どうやらCompSciStudentのトレイトを実装するからと言って、上位集合のメソッドを同時に実装できるわけではないらしい
    • Javaのような継承はないというのはこういうことか...
  • 仕方ないので1個ずつトレイトを実装していく
impl Person for CompSciStudentImpl {
    fn name(&self) -> String { self.0.to_string() }
}
impl Student for CompSciStudentImpl {
    fn university(&self) -> String { self.1.to_string() }
}
impl Programmer for CompSciStudentImpl {
    fn fav_language(&self) -> String { self.2.to_string() }
}
impl CompSciStudent for CompSciStudentImpl {
    fn git_username(&self) -> String { self.3.to_string() }
}
  • これで実行すると以下のように出力された。やったー!
My name is John Doe and I attend test. My favorite language is Rust. My Git username is j_doe

 

[まとめ]

モブプログラミングスタイルでRust dojoを開催した。

to_string()を忘れたり、トレイトの実装方法を間違えたりしたけど今週も楽しくやれた。

 

プルリクエストはそのうち追記予定。