第22回です。
前回はこちら。
[第22回の様子]
2021/12/15に第22回を開催した。
内容としてはRust By Example 日本語版の「8.5.2. ガード」、「8.5.3. バインディング」の途中まで取り組んだ。
参加者は、かなり減って3人だけ。師走だからか、みんな忙しいみたい。それでも参加してくれた2人に感謝。
最初ちょっと集まりが悪かったので雑談をしていたらモブプロの時間が短くなってしまった。反省。
[学んだこと]
- 8.5.2. ガード
- matchの中の条件文にさらにifで条件を追加することができる
fn main() {
let pair = (2, -2);
match pair {
// xとyが同じだったら...
(x, y) if x == y => println!("These are twins"),
// xとyの和が0だったら...
(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
// xが奇数だったら...
(x, _) if x % 2 == 1 => println!("The first one is odd"),
_ => println!("No correlation..."),
}
}
// Antimatter, kaboom!と出力される
- matchでは最初に合致した条件のみが実行される。上記で
let pair = (0, 0);だと1番目と2番目の分岐を満たすが、1番目の分岐のみ実行される。 - ガードをつけると、matchの網羅性チェックが効かなくなるため、必ず最後に
_ => ...,のワイルドカード分岐を実装する必要がある
fn main() {
let number: u8 = 4; // u8型なので0以上の整数
match number {
i if i == 0 => println!("Zero"),
i if i > 0 => println!("Greater than zero"),
// 分岐は網羅されているはずだが...
}
}
// 以下のコンパイルエラー
error[E0004]: non-exhaustive patterns: `_` not covered
--> src/main.rs:4:11
|
4 | match number {
| ^^^^^^ pattern `_` not covered
|
= help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms
= note: the matched value is of type `u8`
- 8.5.3. バインディング
- matchの条件で範囲を利用する場合に、値を変数にバインドできる
fn age() -> u32 {
15
}
fn main() {
match age() {
0 => println!("I haven't celebrated my first birthday yet"),
n @ 1 ..= 12 => println!("I'm a child of age {:?}", n),
n @ 13 ..= 19 => println!("I'm a teen of age {:?}", n),
n => println!("I'm an old person of age {:?}", n),
}
}
// I'm a child of age 15と出力される
- matchさせるのがプリミティブだとあまり気にならないが、構造体の場合deriveするトレイトによって挙動が変わる
Cloneトレイトを実装していない場合、バインドした変数に所有権がうつり、元の変数は利用できなくなる
#[derive(Debug)]
struct Movable { x: i32 }
let a = Movable { x: 100 };
println!("a: {:p}", &a);
// a: 0x7ffc6c1eba34
println!("x: {:p}", &a.x); // &aと同じ値(構造体の最初のメンバなので)
// x: 0x7ffc6c1eba34
match a {
b @ Movable { x: y } => {
println!("Moved a: {:p}", &b);
// Moved a: 0x7ffc6c1ebad8
println!("Captured a.x: {:p}", &y);
// Captured a.x: 0x7ffc6c1ebadc // &bとは異なる。別途キャプチャされているため
// println!("Original a: {:p}", &a);
// ここでは所有権が移動しているため変数aを利用できない
// Cloneトレイトを利用していれば、問題なく利用できる
}
}
- matchする際に、
refを用いて参照にすると、全てのポインタが同じ値をしめす
#[derive(Debug)]
struct Movable { x: i32 }
let a = Movable { x: 100 };
println!("a: {:p}", &a); // a: 0x7ffc6c1ebd24
println!("x: {:p}", &a.x); // x: 0x7ffc6c1ebd24
match a {
ref b @ Movable { x: ref y } => {
println!("Referenced a: {:p}", b);
// Referenced a: 0x7ffc6c1ebd24
println!(" a.x: {:p}", y);
// a.x: 0x7ffc6c1ebd24
println!("Original a: {:p}", &a);
// Original a: 0x7ffc6c1ebd24
}
}
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
1週間ぶりのポインタと参照だと頭がなかなか切り替わらない...。
今週のプルリクエストはこちら。