【问题标题】:Why does compilation not fail when a member of a moved value is assigned to?为什么分配移动值的成员时编译不会失败?
【发布时间】:2018-09-19 07:41:21
【问题描述】:

我正在研究Rust by Example 中的示例。

#[derive(Debug)]
struct Point {
    x: f64,
    y: f64,
}

#[derive(Debug)]
struct Rectangle {
    p1: Point,
    p2: Point,
}

fn main() {
    let mut point: Point = Point { x: 0.3, y: 0.4 };
    println!("point coordinates: ({}, {})", point.x, point.y);

    let rectangle = Rectangle {
        p1: Point { x: 1.0, y: 1.0 },
        p2: point,
    };

    point.x = 0.5; // Why does the compiler not break here,
    println!(" x is {}", point.x); // but it breaks here?

    println!("rectangle is {:?} ", rectangle);
}

我收到此错误(Rust 1.25.0):

error[E0382]: use of moved value: `point.x`
  --> src/main.rs:23:26
   |
19 |         p2: point,
   |             ----- value moved here
...
23 |     println!(" x is {}", point.x);
   |                          ^^^^^^^ value used here after move
   |
   = note: move occurs because `point` has type `Point`, which does not implement the `Copy` trait

我知道我将point 给了Rectangle 对象,这就是为什么我不能再访问它,但是为什么编译失败的是println! 而不是上一行的赋值?

【问题讨论】:

  • 我猜“使用移动的值”可以解释为您尝试读取它的值的点。分配给它并不会真正改变 Rust 在“技术”意义上的保证,只有当您尝试使用移动的值时。也就是说,我自己对其中的大部分内容还不够了解,所以我很想听听更了解这方面的人的意见。
  • 感觉像编译器错误。更有趣的是let p2 = point; point.x = 0.5; println!(" x is {}", p2.x); 编译良好并打印 0.3,所以point.x = 0.5; 什么都不做
  • @qthree 这完全可以预料; Rust 使用值类型,而不是引用类型。

标签: rust


【解决方案1】:

问题是编译器允许对结构进行部分重新初始化,但之后整个结构就无法使用了。即使结构仅包含一个字段,即使您只尝试读取刚刚重新初始化的字段,也会发生这种情况。

struct Test {
    f: u32,
}

fn main() {
    let mut t = Test { f: 0 };
    let t1 = t;
    t.f = 1;
    println!("{}", t.f);
}

这在issue 21232中讨论

【讨论】:

  • 我不清楚这个答案在the existing answer之外提供了什么
  • @Shepmaster 它删除了错误的部分。作为奖励,我添加了对该问题的简要说明,因为仅发布链接是错误的形式。
【解决方案2】:

真正发生了什么

fn main() {
    let mut point: Point = Point { x: 0.3, y: 0.4 };
    println!("point coordinates: ({}, {})", point.x, point.y);

    drop(point);

    {
        let mut point: Point;
        point.x = 0.5;
    }

    println!(" x is {}", point.x);
}

原来它已经被称为issue #21232

【讨论】:

  • 为什么嵌套块中有另一个let mut point?这不会改变问题,因为您要分配的点是一个新点,在内存中与删除的点不同的位置?
  • @AlexKnauth 我认为这个想法是指出编译器看到的情况。也就是说,编译器在那里看到了额外的范围,它有自己的允许赋值的“点”。
  • 因为 point.x = 0.5; 在原始代码中对移动的值没有任何作用,而是尝试初始化新值。
  • 但在原始代码中,该范围不存在,并且它没有创建新的point 变量,而是分配给旧的删除point。还是我误解了它的工作原理?
  • @AlexKnauth 你是对的,因为它在原始代码中不存在。我认为 qthree 的目的是展示编译器看到的内容。编译器看到 OP 的代码,就好像这个额外的范围在那里一样。这就是分配有效的原因,但 println! 行无效。
猜你喜欢
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 2018-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多