5

編集者注: この質問のコードは Rust 1.0 より前のものです。それ以来、セマンティクスが変更され、質問で行われた主張の一部はもはや真実ではありません。

次のコードがあります。

extern crate debug;

use std::mem::size_of_val;

struct A<'a> {
    a: &'a [i64],
}

fn main() {
    // code
}

&次のように(ie &[1, 2, 3])を使用してスライスを定義すると、println!

println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });

出力は

16 - A<'static>{a: &[1i64, 2i64, 3i64]}

なしでスライスを定義する&

println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });

私に同じ結果を与える

16 - A<'static>{a: &[1i64, 2i64, 3i64]}

最初に struct のインスタンスをバインドしようとするとA、そのaフィールドはスライスへの参照で初期化されます (つまり、 を使用&)、変数にx

let x = A { a: &[1, 2, 3] }; // &[1, 2, 3] is a reference to a slice

println!そして、前のものと同様のことを実行しようとします

println!("{} - {:?}", size_of_val(&x), x);

私は得る

16 - A<'static>{a: &[1i64, 2i64, 3i64]}

Aただし、aフィールドがスライスに初期化されている (を使用したスライスへの参照ではない&) のインスタンスを変数にバインドすると、x

let x = A { a: [1, 2, 3] };

println!そして、前のものと同様のことを実行しようとします

println!("{} - {:?}", size_of_val(&x), x);

次のビルド エラーが発生します。

/prpath/main.rs:12:20: 12:29 error: borrowed value does not live long enough
/prpath/main.rs:12     let x = A { a: [1 ,2, 3] };
                                        ^~~~~~~~~
/prpath/main.rs:11:11: 15:2 note: reference must be valid for the block at 11:10...
/prpath/main.rs:11 fn main() {
/prpath/main.rs:12     let x = A { a: [1 ,2, 3] };
/prpath/main.rs:13 
/prpath/main.rs:14     println!("{} - `{:?}`", size_of_val(&x), x);
/prpath/main.rs:15 }
/prpath/main.rs:12:5: 12:31 note: ...but borrowed value is only valid for the statement at 12:4; consider using a `let` binding to increase its lifetime
/prpath/main.rs:12     let x = A { a: [1 ,2, 3] };
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error

型が必要A { a: &[1, 2, 3] }なので定義だけが許可されると思っていましたが、どうやら Rust ではシンボルを含めないように許可されているようです。A.a&[i64]&

A { a: &[1, 2, 3] }とはどう違いA { a: [1, 2, 3] }ますか?なぜ使用が許可されているA { a: [1, 2, 3] }のですか (上記の 2 番目の例)。

4

1 に答える 1

5

[T,..n]まず、 a が期待される場所で aを使用できます&[T]。スライスへの変換は暗黙的です。したがって、次のコードは完全に有効です。

let a = [1u, 2, 3];
let b: &[uint] = a;

あなたの状況は、純粋に一生の問題です。あなたの構造体は

struct A<'a> {
    a: &'a [i64],
}

スライスを保持します。スライスは、最初の要素への参照と要素数のカウントにすぎません。そのためsize_of_val()、a で呼び出されるAと常に 16 が返されます。これは、スライスのサイズであり、ポインタに u64 が 1 つ、要素の数に u64 が 1 つです (64 ビット コンピューターのようです)。

したがって、コードでは、構造体は配列を所有していません。観察される動作の違いは、配列がスコープ外になるタイミングの違いによるものです。

最初のケース:

let x = A { a: [1, 2, 3] };

ここで配列を定義し、構造体のこの配列にスライスを格納します。その後、 に到達する;と、配列はスコープ外になり、破棄されるため、 の参照xは無効になります。コンパイラによって禁止されています。

2 番目のケース:

let x = A { a: &[1, 2, 3] };

それはもっと独特です。配列は匿名変数に格納されます。実際に書くと、

let foo = &42u;

書くことに等しい

let _anonymousvariable = 42u;
let foo = &_anonymousvariable;

_anonymousvariableあなたが直接到達できないことを除いて。

それはあなたにとってまったく同じです、あなたのコードは同等です

let _anonymous_array = [1, 2, 3]
let x = A { a: &_anonymous_array };

したがって、完全に有効です。

最後のケース:

すべてを直接println!(). 前のケースのおかげで、これが機能する理由がわかりました。

println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });

しかし、この場合も問題はありません:

println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });

配列は に到達したときにのみ範囲外になり、;この時点以降はそれらへの参照が存在しないため、安全に削除でき、コンパイラーは満足しています。

于 2014-10-17T20:39:23.620 に答える