为什么指针移动后分配给指针成员仍然有效? [英] Why is assigning to a member of a pointer still valid after the pointer is moved?

查看:42
本文介绍了为什么指针移动后分配给指针成员仍然有效?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Why is n1_mut still valid in this example? It has been moved into Option::Some so shouldn't it be invalid?

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

以下不会编译时出现熟悉的使用移动值"错误:

The following does not compile with the familiar "use of moved value" error:

#[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

推荐答案

这与是否为指针无关;这也有效:

This doesn't have anything to do with being a pointer or not; this works as well:

#[derive(Debug)]
struct NonCopy;

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

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

    drop(foo);

    foo.name = NonCopy;
}

虽然我找不到我以前见过的类似的 SO 问题,但是这个 引自 nikomatsakis 描述了它:

Although I can't find the similar SO question that I know I've seen before, this quote from nikomatsakis describes it:

一般来说,在非常窄的粒度级别上跟踪移动.我们打算最终允许您重新填充"这两个字段,然后再次使用该结构.我想这在今天不起作用.我必须再次查看移动代码,但我认为总的来说,我想在 1.0 后追求的一件事是扩展类型系统以更好地处理已移动的事物(特别是我想支持移出 &mut 指针,只要您在做任何可能出错的事情之前恢复该值).无论如何,我认为这个例子或多或少不以一般的方式对待事物,尽管你可以想象这样的规则:如果你移动 f,你不能再触摸 f 的任何子域,而不会将 f 恢复为一个单位".

In general moves are tracked at a pretty narrow level of granularity. We intend to eventually permit you to "fill" both fields back in and then use the structure again. I guess that doesn't work today. I have to go look again at the moves code, but I think in general one of the things I'd like to pursue post 1.0 is extending the type system to deal better with things that have been moved from (in particular I want to support moves out of &mut pointers, so long as you restore the value before doing anything fallible). Anyway I think this example more-or-less falls out of treating things in a general way, though you could imagine rules that say "if you move f, you can never again touch any subfields of f without restoring f as a unit".

还有关于 Rust subreddit 的讨论,它链接到 Rust issue 21232:借用检查器允许部分重新初始化结构已移走,但未使用"

There's also discussion on the Rust subreddit, which links to Rust issue 21232: "borrow-checker allows partial reinit of struct that has been moved away, but no use of it"

从概念上讲,除了结构本身之外,结构中的每个字段都有一个标志——我喜欢想到 Chris Morgan 的纸板箱比喻.只要在使用结构体之前移回,就可以移出拥有的结构体的字段:

Conceptually, there's a flag for each of the fields in a struct in addition to the struct itself — I like to think of Chris Morgan's cardboard box analogy. You can move out of an owned struct's field so long as you move back in before using the struct:

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

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

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

Evidently, since 2014, no one has bothered to put in the effort to enable marking the entire struct as valid again once the fields are re-filled.

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

Realistically, you don't really need this functionality as you can just assign the entire variable at once. The current implementation is overly-safe as Rust is preventing you from doing something that seems OK.

这篇关于为什么指针移动后分配给指针成员仍然有效?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆