Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

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 here

For 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)のパターンのメモ

参照の分配

クロージャの引数のところ

https://doc.rust-jp.rs/book-ja/ch18-03-pattern-syntax.html?highlight=Point#%E5%8F%82%E7%85%A7%E3%82%92%E5%88%86%E9%85%8D%E3%81%99%E3%82%8B

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)); // これ!