51652


Rust言語では `ref` パターンを使って右辺の式の参照を暗に取る事ができると思います。

[code]

    // Copyではない適当な型
    struct Val{
        value: u32
    }
    
    fn main() {
        let x: Val = Val { value: 32 };
        let rx1: &Val = &x; // 普通に参照を取る
        let ref rx2: Val = x; // 参照を暗に取る
        let ref rx3: Val = x; // 何度でも取れる
        println!("{}", x.value); // 単に参照をとっているだけなのでmoveされておらずxは使える
    }
    
[/code]

この文法を関数引数で使ってみます。

[code]

    struct Val {
        value: u32
    }
    
    // refでとってみる
    fn test(ref v: Val) {
        println!("test: {}", v.value)
    }
    
    fn main() {
        let x: Val = Val { value: 32 };
        test(x); // しかし残念ながらここでmoveされていて
        test(x) // コンパイルエラー(value used here after move)
    }
    
[/code]

しかしこの場合は引数はmoveされてしまい、二度使う事ができません。  
こういう形でrefを使った場合にxがmoveされる理由をご存知の方がいたら教えて頂けませんか。


CC BY-SA 4.0
2019-01-01T06:50:49.103
51647
2019-01-01T10:23:09.823
30827
question
rust
関数引数でのrefパターンがmoveを生じさせる理由を知りたい


`let x: Val`のとき`test(x)`とすると、関数の引数は「値渡し」になります。値渡しでは、値が関数の引数の領域へmoveします。

`main`ではスタック領域上に`x`のための領域があります。

[code]

    mainのスタックフレーム
      x    | Val { value: 32}
    
[/code]

`test`を呼ぶと、まず`main`の`x`の値が、`test`の引数の領域（`arg0`としました）にmoveします。

[code]

    testのスタックフレーム
      v    | 初期化されてない状態
      arg0 | Val { value: 32}
    
    mainのスタックフレーム
      x    | 初期化されてない状態（move済み）
    
[/code]

そして`v`には`arg0`への参照が置かれます。

[code]

    testのスタックフレーム
      v    | &arg0
      arg0 | Val { value: 32}
    
    mainのスタックフレーム
      x    | 初期化されてない状態（move済み）
    
[/code]

これを擬似的なコードで示すと、以下のようになります。

[code]

    fn test(arg0: Val) {
        let ref v = arg0;
        println!("test: {}", v.value)
    }
    
[/code]

このように動作しますので、`x`の値がmoveするわけです。

参考： <https://users.rust-lang.org/t/ref-and-for-function-arguments/12790>


CC BY-SA 4.0
2019-01-01T10:23:09.823
51652
2019-01-01T10:23:09.823
14101
51647
answer