锈 – 通过参考和盒子之间的差异

前端之家收集整理的这篇文章主要介绍了锈 – 通过参考和盒子之间的差异前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
通过引用和方框通过值与函数之间有什么区别?
fn main() {
    let mut stack_a = 3;
    let mut heap_a = Box 3;

    foo(&mut stack_a);
    println!("{}",stack_a);

    let r = foo2(&mut stack_a);
    // compile error if uncomment next line
    // println!("{}",stack_a);

    bar(heap_a);
    // compile error if uncomment next line
    // println!("{}",heap_a);

}

fn foo(x: &mut int){
    *x = 5;
}

fn foo2(x: &mut int) -> &mut int{
    *x = 5;
    x
}

fn bar(mut x: Box<int>){
    *x = 5;
}

为什么heap_a移动到函数,但stack_a不是(stack_a仍然可用在println!调用foo后)?

碎片碎片:

`heap_a` moved here because it has type `Box<int>`,which is non-copyable

我假设这在某种程度上取决于生命,因为在“foo2”的情况下,“stack_a”也移动到函数。如果我的假设是真的,如果“foo”,“stack_a”也移动到函数,但是rustc发现,它的生命周期结束于“foo”结尾,并允许在“foo”结束后使用“stack_a”。那么为什么“heap_a”的生命没有结束在“bar”的结尾?

解决方法

Pass-by-value总是是副本(如果涉及的类型是“微不足道”)或移动(如果不是)。盒及LT; INT>不可复制,因为它(或其至少一个数据成员)实现Drop。这通常用于某种“清理”代码。盒子< int>是一个“拥有的指针”。这是它所指向的唯一所有者,这就是为什么“感觉到负责”释放int的记忆在它的放弃功能。想象一下,如果你复制了一个Box< int>:现在,你会有两个Box< int>指向同一内存位置的实例。这将是坏的,因为这会导致双重错误。这就是为什么bar(heap_a)移动Box< int>实例进入吧。这样一来,总是只有一个heap-assigned int的所有者。这使得管理内存很简单:谁拥有它,最终释放它。

与foo(& mut stack_a)的区别在于您不通过值传递stack_a。你只需要“借出”foo stack_a,这样一来,foo能够改变它。什么是获得的是一个借用的指针。当执行从foo回来时,stack_a仍然存在(可能通过foo修改)。你可以将它看作是stack_a返回到自己的堆栈框架,因为foo只是借了一会儿。

似乎混淆你的部分是通过取消注释最后一行

let r = foo2(&mut stack_a);
// compile error if uncomment next line
// println!("{}",stack_a);

你实际上没有测试stack_a是否被移动。 stack_a还在那里编译器根本不允许您通过其名称访问它,因为您仍然可以借用它引用它:r。这是我们需要的内存安全规则之一:如果我们也允许改变它,只能有一种访问内存位置的方法。在这个例子中,r是一个可以借用的stack_a引用。所以,stack_a仍被认为是可借用的。访问它的唯一方法是通过借用的引用r。

使用一些额外的花括号,我们可以限制借用引用的生命周期r:

let mut stack_a = 3i;
{
   let r = foo2(&mut stack_a);
   // println!("{}",stack_a); WOULD BE AN ERROR
   println!("{}",*r); // Fine!
} // <-- borrowing ends here,r ceases to exist
// No aliasing anymore => we're allowed to use the name stack_a again
println!("{}",stack_a);

关闭括号后,只有一种访问内存位置的方法名称stack_a。这就是为什么编译器让我们在println!中使用它。

现在你可能会想,编译器如何知道r实际上是指stack_a?是否分析了foo2的实现?不,没有必要。 foo2的功能签名就足以得出这个结论。它的

fn foo2(x: &mut int) -> &mut int

这实际上是短的

fn foo2<'a>(x: &'a mut int) -> &'a mut int

根据所谓的“终身检验规则”。这个签名的含义是:foo2是一个函数,它使用一个借用的指针到一些int,并返回一个借用的指针,这个int指针是同一个int(或至少是原始int的“part”),因为同一个生命周期参数用于返回类型。只要你坚持这个返回值(r),编译器就认为stack_a可以借用。

如果您有兴趣为什么我们需要同时禁止别名和(潜在)突变发生。一些记忆位置,查看Niko’s great talk

猜你在找的CSS相关文章