简体   繁体   English

如何理解 rust 中的 deref 和所有权?

[英]How to understand the deref and ownership in rust?

this is error:这是错误:

struct A(i32);

fn main(){
    let a = A(1);
    let ra = &a;
    let x = *ra;
}

but this is ok(only change & to Box::new ):但这没关系(仅将&更改为Box::new ):

struct A(i32);

fn main(){
    let a = A(1);
    let ra = Box::new(a);
    let x = *ra;
    // (1)
}

what is happenning here?这里发生了什么?

when I add this at (1):当我在 (1) 添加这个时:

let ra2 = ra;

it say "use of moved value: ra ".它说“使用移动值: ra ”。 But I just move the *ra .但我只是移动了*ra if in seconed code it moves ra, then in first code why it doesn't move ra?如果在第二个代码中它移动 ra,那么在第一个代码中为什么它不移动 ra?

I write my box(via The Rust Programming Language 15.2), but it also cannot moves ra, and report an error:我写了我的盒子(via The Rust Programming Language 15.2),但是它也不能移动ra,报错:

use std::ops::Deref;
struct A(i32);

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

fn main(){
    let a = A(1);
    let ra = MyBox::new(a);
    let x = *ra;
}

In your first example what happened:在你的第一个例子中发生了什么:

struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a` variable
    let ra = &a; // `ra` references to `a`. 
    println!("{}", a.0); // `a` itself is still exists here and you can read it
    let x = *ra; // A(1) is being tried to be moved from `a`. Error here
    let x = a; // but you can move value from `a` directly. It's ok here.
    // `a` does not exist any more
    // println!("{}", a.0); // error here 
}

In the line let x = *ra;在行中let x = *ra; you are trying to "extract" value from behind the reference.您正试图从参考后面“提取”价值。 But ra does not own the value.ra不拥有该值。 It owned by a .它由a . So you can't move value from variable, if this variable does not own it.所以你不能从变量中移动值,如果这个变量不拥有它。

In your second example different thing happened.在您的第二个示例中,发生了不同的事情。

struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a`
    let ra = Box::new(a); // value `A(1)` is moved from `a` to boxed.
    // you can't access to `a` now:
    // println!("{}", a.0); // error here
    let x = *ra; // here you are trying to move value from the memory location where `Box` points to.
    // `ra` does not exist any more!
    // println!("{}", ra.0); // error here. Used of moved value
}

Box owns A(1) . Box拥有A(1) As long as there is no references to A(1) you can move value behind the Box .只要没有对A(1)引用,您就可以将值移到Box后面。

If you will try to get reference to the value behind the Box , then you also can't move by dereferencing:如果您尝试获取对Box背后的值的引用,那么您也无法通过取消引用来移动:

struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a`
    let ra = Box::new(a); // value `A(1)` is moved from `a` to box.
    let ra_ref = &ra;
    // both `ra_ref` and `ra` are accesseble here
    
    // let x = *ra; // here you are trying to move value from the memory location where `Box` points to. Error as long as there `ra_ref`
    println!("{}", ra_ref.0);
}

According to Moved and Copyed Types根据移动和复制类型

When a place expression is evaluated in a value expression context, or is bound by value in a pattern, it denotes the value held in that memory location.当一个位置表达式在值表达式上下文中被评估,或者被模式中的值绑定时,它表示在该 memory 位置中保存的值。 If the type of that value implements Copy, then the value will be copied.如果该值的类型实现了 Copy,那么该值将被复制。 In the remaining situations, if that type is Sized, then it may be possible to move the value.在其余情况下,如果该类型是 Sized,则可以移动该值。 Only the following place expressions may be moved out of:只能移出以下位置表达式:

  • Variables which are not currently borrowed.当前未借用的变量。
  • Temporary values.临时值。
  • Fields of a place expression which can be moved out of and don't implement Drop.可以移出并且不实现 Drop 的位置表达式的字段。
  • The result of dereferencing an expression with type Box and that can also be moved out of.取消引用具有 Box 类型的表达式的结果,也可以将其移出。
struct A(i32);

fn main(){
    let a = A(1); // A(1) is in `a`
    let ra = Box::new(a); // value `A(1)` is moved from `a` to box.

    // `ra` is a place expression(`ra` is a variable), 
    // and it is evaluated in a value expression context. According to that 
    // rule, if `ra` is a Box, then the move semantic happens. so this is ok.

    let b = ra; 
    }

But for this code但是对于这段代码

struct A(i32);

fn main() {
    let a = A(1);
    let ra = &a; // ra is a borrow of a
    let b = *ra; // `*ra` is also a place expression according to
    // the definition of `place expr and value expr`
    // and *ra is in a value expression context, so it is referencing
    // the value of `ra`, i.e. `a` with type `A`, `A` does not impl Copy
    // so it may be moved, but it does not satisfy the above four moving
    // rules. So, an error will occur.
}

place expr and value expr 放置 expr 和值 expr

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM