Rust でブロック内に定義した関数とか構造体とかはそのスコープで閉じる
メモ。
関数とか構造体とかは外側で定義してるイメージだけど、別にどこでも定義できるらしい。
でもスコープが発生するので見えないところからは使えないらしい。
fn main() { { #[derive(Debug)] struct Foo; let foo = Foo {}; println!("{:?}", foo); } { let foo = Foo {}; println!("{:?}", foo); } { fn bar() { println!("bar"); } bar(); } { bar(); } }
error[E0422]: cannot find struct, variant or union type `Foo` in this scope --> src\main.rs:9:19 | 9 | let foo = Foo {}; | ^^^ not found in this scope error[E0425]: cannot find function `bar` in this scope --> src\main.rs:18:9 | 18 | bar(); | ^^^ not found in this scope
Rust で配列の要素そのもので配列にアクセスしようとするとエラー
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
エラーが出たのでメモ。
やりたいこと。
fn main() { let mut v: Vec<usize> = vec![3, 123, 234, 345, 456, 567]; v[v[0]] *= 100; // 要素 3 を 100 倍する println!("{:?}", v); }
起きたエラー。
error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
--> src/main.rs:3:7
|
3 | v[v[0]] *= 100;
| --^----
| | |
| | immutable borrow occurs here
| mutable borrow occurs here
| mutable borrow later used hereFor more information about this error, try `rustc --explain E0502`.
|
日本語意訳。
"v" はミュータブルとして借用されているので、イミュータブルとして借用できません。
いまひとつ理解に至らないが、v のベクタ自体がミュータブルな配列で、この再代入の式自体が mut の効果を持ち、添え字として取り出そうとした v[1] の部分がイミュータブルのアクセスとして取得しようとして、それで引っかかっている、ということか?
let (v1, v2) = (&mut v, &v); ってしたら同じように怒られるから、こんな感じか?
とりあえず別に束縛して暗黙コピーしたらちゃんと動いた。
let mut v: Vec<usize> = vec![3, 123, 234, 345, 456, 567]; let vv = v[0]; v[vv] *= 100; println!("{:?}", v); // [3, 123, 234, 34500, 456, 567]
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)); // これ!