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字段是使用对切片的引用(即 using )初始化的&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] }允许定义,因为A.a应该有&[i64]类型,但显然,Rust 允许我们不包含&符号。

A { a: &[1, 2, 3] }和 和有什么不一样A { a: [1, 2, 3] }?为什么我们允许使用A { a: [1, 2, 3] }(在上面的第二个示例中)?

4

1 回答 1

5

首先,您可以在预期a 的[T,..n]地方使用 a,转换为 slice 是隐式的。&[T]所以下面的代码是完全有效的:

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

您的情况纯粹是一生的问题。你的结构是

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

它有一片。切片只不过是对第一个元素的引用和元素数量的计数。这就是为什么size_of_val()调用 aA将始终返回 16:它是切片的大小,一个 u64 用于指针,一个 u64 用于元素数量(就像您在 64 位计算机上一样)。

因此,在您的代码中,结构不拥有数组。您观察到的行为差异是由于数组超出范围时的差异。

第一种情况:

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

在这里,您定义了一个数组,并将切片存储到您的结构中的该数组中。然后,当到达 时;,您的数组超出范围并被销毁,因此 in 的引用x不再有效:编译器禁止它。

第二种情况:

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 回答