为什么n1_mut在这个例子中仍然有效?它已经被移到Option::Some了,所以它不应该是无效的吗?

struct MyRecordRec2<'a> {
    pub id: u32,
    pub name: &'a str,
    pub next: Box<Option<MyRecordRec2<'a>>>
}

#[test]
fn creating_circular_recursive_data_structure() {
    let mut n1_mut = MyRecordRec2 {
        id: 1,
        name: "n1",
        next: Box::new(None)
    };

    let n2 = MyRecordRec2 {
        id: 2,
        name: "n2",
        next: Box::new(Some(n1_mut))
    };

    //Why is n1_mut still valid?
    n1_mut.next = Box::new(Some(n2));
}

以下代码没有使用常见的"使用移动值"错误进行编译:

#[test]
fn creating_and_freezing_circular_recursive_data_structure() {
    let loop_entry = {
        let mut n1_mut = MyRecordRec2 {
            id: 1,
            name: "n1",
            next: Box::new(None),
        };

        let n2 = MyRecordRec2 {
            id: 2,
            name: "n2",
            next: Box::new(Some(n1_mut)),
        };

        n1_mut.next = Box::new(Some(n2));

        n1_mut
    };
}
error[E0382]: use of moved value: `n1_mut`
  --> src/main.rs:44:9
   |
39 |             next: Box::new(Some(n1_mut)),
   |                                 ------ value moved here
...
44 |         n1_mut
   |         ^^^^^^ value used here after move
   |
   = note: move occurs because `n1_mut` has type `MyRecordRec2<'_>`, which does not implement the `Copy` trait

推荐答案

这与是否是指针无关;这同样有效:

#[derive(Debug)]
struct NonCopy;

#[derive(Debug)]
struct Example {
    name: NonCopy,
}

fn main() {
    let mut foo = Example {
        name: NonCopy,
    };

    drop(foo);

    foo.name = NonCopy;
}

虽然我找不到类似的问题,我知道我以前见过,这quote from nikomatsakis个描述:

一般来说,移动的跟踪粒度非常窄.我们打算最终允许您"填充"这两个字段,然后再次使用该 struct .我想今天不行.我必须再看一次moves代码,但我认为在1.0之后,我想做的一件事是扩展类型系统,以便更好地处理从中移出的内容(特别是我想支持移出&;mut指针,只要在做任何可能出错的事情之前恢复值).无论如何,我认为这个例子或多或少不符合一般的处理方式,尽管你可以想象规则说"如果你移动f,你再也不能接触f的任何子字段而不将f恢复为一个单位".

还有关于the Rust subreddit的讨论,链接到Rust issue 21232: "borrow-checker allows partial reinit of struct that has been moved away, but no use of it"

从概念上讲,除了 struct 本身, struct 中的每个字段都有一个标志——我想是Chris Morgan's cardboard box analogy.只要在使用 struct 之前搬回,就可以移出所属 struct 的字段:

drop(foo.name);
foo.name = NonCopy;

println!("{:?}", foo);

显然,自2014年以来,没有人费心在字段重新填充后再次将整个 struct 标记为有效.

实际上,你并不真的需要这个功能,因为你可以一次分配整个变量.当前的实现过于安全,因为Rust 会阻止你做一些看起来还行的事情.

Rust相关问答推荐

将内部类型作为参数的泛型 struct 上的方法

如何找到一个数字在二维数组中的位置(S)?

如何将元素添加到向量并返回对该元素的引用?

"value is never read警告似乎不正确.我应该忽略它吗?

为什么铁 rust S似乎有内在的易变性?

闭包不会发送,即使它只捕获发送变量

如何导入crate-type=[";cdylib;]库?

try 创建随机数以常量

习语选项<;T>;到选项<;U>;当T->;U用From定义

考虑到Rust不允许多个可变引用,类似PyTorch的自动区分如何在Rust中工作?

Tokio';s io::用Cursor拆分<;Vec<;u8>>;赢得';t get the full writted data

用于实现获取 struct 体 id 的特征规范

为什么实现特征的对象期望比具体对象有更长的生命周期?

Rust:为什么 Pin 必须持有指针?

如何基于常量在Rust中跳过一个测试

Rust中的位移操作对范围有什么影响?

Rust编译器通过哪些规则来确保锁被释放?

如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

std::vector::shrink_to_fit 如何在 Rust 中工作?

为什么这个值在上次使用后没有下降?