首页 文章

使用带切片的结构时,“借来的值不够长”

提问于
浏览
5

编者注:此问题中的代码早于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 回答

  • 5

    首先,您可以使用 [T,..n] ,其中 &[T] 是预期的,转换为切片是隐式的 . 所以下面的代码是完全有效的:

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

    你的情况纯属终身问题 . 你的结构是

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

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

    所以在你的代码中, the struct does not own the array . 您观察到的行为差异是由于阵列超出范围时的差异 .

    First case:

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

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

    Second case:

    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 };
    

    因此是完全有效的 .

    Last case:

    当您直接在 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] });
    

    因为你的数组在到达 ; 时只会超出范围,并且在此之后不存在对它们的引用,因此可以安全地删除它们并且编译器很高兴 .

相关问题