Rust 参照の分配(destructuring)のパターンのメモ
参照の分配
クロージャの引数のところ
VS Code が教えてくれる書き方の中に、クロージャの引数部分で、|&x| のように & がついていて、参照なのか何なのかよくわからないな、let の変数束縛時に左辺に & つけないし……、と思ってたら↑に書いてあった。
|&x| と書くと、x はむき出し状態として使うことができる。
下の例は、iter() も filter() も、要素が参照になるので、つなげると &&T が filter 内部に伝わっている。
let v: Vec<String> = vec![ String::from("foo"), String::from("bar"), String::from("baz"), String::from("foo"), ]; // String と &str は比較可能みたいです // |&s| にしたら s は &String になる let v2: Vec<&String> = v.iter().filter(|&s| s == "foo").collect(); // let v2: Vec<&String> = v.iter().filter(|&s| (*s).eq("foo")).collect(); println!("v2: {:?}", v2); // v2: ["foo", "foo"] // |s| にしたら s は &&String になる // 自動で一つデリファレンスされての比較では、「can't compare `&String` with `str`」エラーになる // let v3: Vec<&String> = v.iter().filter(|s| s == "foo").collect(); // 手動で一つデリファレンスすると動く let v3: Vec<&String> = v.iter().filter(|s| *s == "foo").collect(); println!("v3: {:?}", v3); // v3: ["foo", "foo"] // もちろん手動で二つデリファレンスも OK let v3: Vec<&String> = v.iter().filter(|s| **s == "foo").collect(); // |&&s| にすると、いきなりむき出しになるが、暗黙のコピーが発生するらしく、Vec<String> だとエラーになってしまった let v4: Vec<&String> = v.iter().filter(|&&s| s == "foo").collect(); // error[E0507]: cannot move out of a shared reference // move occurs because `s` has type `String`, which does not implement the `Copy` trait
Copy トレイト実装済のプリミティブな型なら |&&s| でもいける。
let vv = vec![1, 2, 3]; let v5: Vec<_> = vv.iter().filter(|&&s| s == 2).collect(); // s は i32 println!("v5: {:?}", v5); // v5: [2]
Enum のデータのところ
if let とか、match とかで、Some(T) のデータ部分も &x みたいに & をつけてむき出しで使える。
let s = "foo"; let ss: Option<&&str> = Some(&s); if let Some(&s1) = ss { println!("{}", s1); // s1 は &str } match ss { Some(&s2) => println!("{}", s2), // s2 は &str _ => (), }
でもこれも Copy トレイトを実装している必要があるので、String だとエラーになった。
あと & って変数とか型とかだけではなく、値に直接つけることもできるというのをメモ。
let i = 123; let o = Some(&i); assert_eq!(o, Some(&123)); // これ!