Rust の構造体の分配(destructuring)などのパターン記法のメモ
その1
変数を構造体のインスタンスから生成することができるとのこと。
https://doc.rust-jp.rs/book-ja/ch18-03-pattern-syntax.html#%E5%88%86%E9%85%8D%E3%81%97%E3%81%A6%E5%80%A4%E3%82%92%E5%88%86%E8%A7%A3%E3%81%99%E3%82%8B
↑これのやつ。
struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; // ここで構造体の中身を使って変数を生成するのすごくない? // 変数 a と変数 b ができてる let Point { x: a, y: b } = p; assert_eq!(0, a); assert_eq!(7, b); }
別に変数名をフィールドと別の名前を使う必要はなくて、変数 x と変数 y でいいならもっと省略して、
let Point { x, y } = p;
と書けるらしい。すご。でも let (x, y) = (p.x, p.y); って書いた方がわかりやすいとも思う。
似たようなので、
struct Point { x: i32, y: i32, } fn main() { let p = Point { x: 0, y: 7 }; match p { Point { x, y: 0 } => println!("On the x axis at {}", x), Point { x: 0, y } => println!("On the y axis at {}", y), // これがマッチ Point { x, y } => println!("On neither axis: ({}, {})", x, y), }
パターンマッチングでもできるらしい。
その2
マッチングのアームで if を使うやつ。
https://doc.rust-jp.rs/book-ja/ch18-03-pattern-syntax.html#%E3%83%9E%E3%83%83%E3%83%81%E3%82%AC%E3%83%BC%E3%83%89%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%AE%E6%9D%A1%E4%BB%B6%E5%BC%8F
↑後置 if っぽいことが「マッチガード」として書けるが、Perl とか Ruby で慣れていた身としては処理の流れが左から右の見たままになっていて、ちょっと混乱した。
let num = Some(4); match num { // num が Some(x) に当てはまり、x < 5 でもあるときマッチ Some(x) if x < 5 => println!("less than five: {}", x), // num が Some(x) のときマッチ Some(x) => println!("{}", x), None => (), }
その3
その1もその2も、所有権が移動してしまうので、移動させたくない場合は ref キーワードを使えばよいようだ。
これもプリミティブな型の場合暗黙的なコピーが発生するので、それがデフォルトの挙動だと思いがちだが、そうでない場合になって初めて気が付く(気が付いた)。
// コンパイルエラーとなる struct Point { x: String, y: String, } fn main() { let p = Point { x: "xxx".to_string(), y: "yyy".to_string() }; let Point { x, y } = p; // - - value moved here println!("x: {}, y: {}", x, y); println!("p.x: {}, p.y: {}", p.x, p.y); }
ref を使う
let Point { x, ref y } = p; // p.x は移動させたままなのでもう使えない println!("x: {}, y: {}", x, y); // println!("p.x: {}, p.y: {}", p.x, p.y); println!("p.y: {}", p.y);
x: xxx, y: yyy p.y: yyy