编者注:此问题中的代码早于Rust 1.0 . 从那以后,语义发生了变化,问题中的一些断言不再成立 .
我有以下代码:
extern crate debug;
use std::mem::size_of_val;
struct A<'a> {
a: &'a [i64],
}
fn main() {
// code
}
当我使用 &
(即 &[1, 2, 3]
)定义切片时,如下所示 println!
println!("{} - {:?}", size_of_val(&A { a: &[1, 2, 3] }), A { a: &[1, 2, 3] });
输出是
16 - <'静态> {a:&[1i64,2i64,3i64]}
在没有 &
的情况下定义切片
println!("{} - {:?}", size_of_val(&A { a: [1, 2, 3] }), A { a: [1, 2, 3] });
给了我相同的结果
16 - <'静态> {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:&[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错误:借来的 Value 不够长
/prpath/main.rs:12让x = A {a:[1,2,3]};
^ ~~~~~~~~
/prpath/main.rs:11:11:15:2注意:引用必须在11:10对块有效...
/prpath/main.rs:11 fn main(){
/prpath/main.rs:12让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注意:......但借来的值仅对12:4的声明有效;考虑使用let
绑定来增加其生命周期
/prpath/main.rs:12让x = A {a:[1,2,3]};
^ ~~~~~~~~~~~~~~~~~~~~~~~~~
错误:由于先前的错误而中止
我期待只允许 A { a: &[1, 2, 3] }
定义,因为 A.a
应该具有 &[i64]
类型,但显然,Rust允许我们不包含 &
符号 .
A { a: &[1, 2, 3] }
和 A { a: [1, 2, 3] }
之间有什么区别?为什么我们允许使用 A { a: [1, 2, 3] }
(在上面的第二个例子中)?
1 回答
首先,您可以使用
[T,..n]
,其中&[T]
是预期的,转换为切片是隐式的 . 所以下面的代码是完全有效的:你的情况纯属终身问题 . 你的结构是
它拥有 slice . 切片只不过是对第一个元素的引用和元素数量的计数 . 这就是为什么
size_of_val()
调用A
将始终返回16:它是一个切片的大小,一个u64用于指针,一个u64用于元素数量(就像你似乎在64位计算机上) .所以在你的代码中, the struct does not own the array . 您观察到的行为差异是由于阵列超出范围时的差异 .
First case:
在这里定义一个数组,并在结构中将切片存储到此数组中 . 然后当到达
;
时,您的数组超出范围并被销毁,因此x
中的引用不再有效:编译器禁止它 .Second case:
它更奇特 . 您的数组存储在匿名变量中 . 实际上,写作
相当于写作
除非你不能直接到达
_anonymousvariable
.这对你来说完全一样,你的代码相当于
因此是完全有效的 .
Last case:
当您直接在
println!()
中写入所有内容时 . 感谢前面的案例,我们现在看看为什么这样做:但在这种情况下也没有问题:
因为你的数组在到达
;
时只会超出范围,并且在此之后不存在对它们的引用,因此可以安全地删除它们并且编译器很高兴 .