第9回です。
前回はこちら。
[第9回の様子]
2021/09/08に第9回を開催した。
内容としてはRust By Example 日本語版の「3. カスタム型」、「3.1. 構造体」を読んで手を動かした。残念ながら最後の演習までは時間が足りず。
参加者は全部で12人。なんかすごい増えたぞ!
今回も、前回終了時に決めておいたメンバーがドライバーを担当。
Slackでのやりとりはちょっと減ってきた。
いらっしゃいませー。
レポートありがとうございます!
復習してえらい!
[学んだこと]
- 3. カスタム型
- カスタム型はstructもしくはenumを使う
- 他に定数を定義するのにstaticとかconstが使える(詳細は3.3で後述)
- 3.1. 構造体
- まずはstructで定義する構造体:ユニット、タプル、構造体の3種類ある
- ユニットはフィールドを持たず、ジェネリック型を使う:よくわからないけど多分14章がジェネリクスなので、そこでまた出てきそう
// ユニットの例 struct Nil; // インスタンス化 let _nil = Nil;
- タプルは名前付きタプル
// フィールドに名前がないのがタプル struct Pair(i32, f32);
- 構造体はフィールドに名前がある
#[derive(Debug)] struct Person<'a> { name: &'a str, age: u8, }
- ここで
'a
はnameがstrの参照なので、Personと寿命を揃えるために必要らしい - Personのインスタンスを作成する場合は次のようになる
let name = "Peter"; let age = 27; let peter = Person { name, age }; println!("{:?}", peter); // Person { name: "Peter", age: 27 }
- 変数nameの型はstrだからPersonを生成する際に
&name
のようにして参照を渡す必要があるのでは?と思ったがそうではないらしい。フィールド名と一致している場合はよろしくやってくれるのだろうか。
let peter = Person { &name, age }; // ↑だけだとコンパイルエラー error: expected identifier, found `&` --> src/main.rs:37:26 | 37 | let peter = Person { &name, age }; | ------ ^ expected identifier | | | while parsing this struct error[E0063]: missing field `name` in initializer of `Person<'_>` --> src/main.rs:37:17 | 37 | let peter = Person { &name, age }; | ^^^^^^ missing `name` error: aborting due to 2 previous errors
- 以下のようにフィールド名を明示すると動く
let peter = Person { name: &name, age };
- 構造体をほかの構造体のフィールドにもできる
struct Point { x: f32, y: f32, } struct Rectangle { top_left: Point, bottom_right: Point, }
- 構造体を作る際に、別のインスタンスのフィールドの値を転用できる:フィールド数が多い場合は便利かも
let point: Point = Point { x: 10.3, y: 0.4 }; println!("point coordinates: ({}, {})", point.x, point.y); // 10.3 0.4 let bottom_right = Point { x: 5.2, ..point }; println!("second point: ({}, {})", bottom_right.x, bottom_right.y); // 5.2 0.4
..point
の部分が後ろにあるとなんかそっちの値でxが上書きされそうで嫌だったが、..point
を先に書くとコンパイルエラーとなってしまった
let bottom_right = Point { ..point, x: 5.2 }; // 以下のコンパイルエラー。元になる構造体は必ず最後でないとダメらしい error: cannot use a comma after the base struct --> src/main.rs:52:32 | 52 | let bottom_right = Point { ..point, x: 5.2 }; | ^^^^^^^- help: remove this comma | = note: the base struct must always be the last field
- 構造体のフィールドを別の変数に分割代入する場合は、
let 構造体名 { 元フィールド名: 代入先の変数名, ... } = インスタンス;
のように書く
struct Point { x: f32, y: f32, } let point: Point = Point { x: 10.3, y: 0.4 }; // 分割代入 let Point { x: top_edge, y: left_edge } = point; println!("{} {}", top_edge, left_edge); // 10.3 0.4
- 分割代入する元の構造体の型は分かっているのだから、構造体名を明示しなくてもよいのでは?と思い実験してみたがコンパイルエラーとなった
let { x: top_edge, y: left_edge } = point; // 以下のエラー error: expected pattern, found `{` --> src/main.rs:60:9 | 60 | let { x: top_edge, y: left_edge } = point; | ^ expected pattern
- タプルも分割代入できる(元フィールド名がないので、代入先変数名のみ)
struct Pair(i32, f32); let pair = Pair(1, 0.1); println!("pair contains {:?} and {:?}", pair.0, pair.1); // 1 0.1 // 分割代入 let Pair(integer, decimal) = pair; println!("pair contains {:?} and {:?}", integer, decimal); // 1 0.1
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
来週は演習からだ。楽しみ!
今週のプルリクエストはこちら。