第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を開催した。
来週は演習からだ。楽しみ!
今週のプルリクエストはこちら。