【问题标题】:How do I retrieve an item from a Vec that is moved into a structure?如何从移动到结构中的 Vec 检索项目?
【发布时间】:2019-08-27 15:23:07
【问题描述】:

我有一个包含结构向量的结构,例如

fn main() {
    let x: Vec<Item> = Vec::new(); 
    // assume x is filled with stuff
    do_things_with(x);
}

struct Item {
    value: String,
}

struct Context {
    x: Vec<Item>,
}

impl Context {
    fn get(&mut self, at: usize) -> Item {
        self.x[at]
    }
}

fn do_things_with(x: Vec<Item>) {
    let mut ctx = Context{
        x: x,
    };
    ctx.get(5);
}

我有一个 Vec 的东西,我将它传递给某个函数,该函数创建一个上下文并将传递的值存储在该结构中。然后我想看看这个 Vec 中的项目,所以我有一些辅助函数,例如'get' 将获取指定索引处的项目。

这看起来一切都很好,在 C 或任何语言中都可以,但是 Rust 抱怨:

'cannot move out of borrowed content'

对于函数“get”,我们尝试访问向量中的项目。

我在这里做错了什么?

【问题讨论】:

    标签: rust borrow-checker


    【解决方案1】:

    这里的问题是Vec 拥有它所包含的Items 的所有权,但Context.get 试图直接返回Item(并取得它的所有权)。

    如果Context.get 只需要让调用者查看向量的内容,它应该返回对项目的引用而不是项目:

    impl Context {
        fn get(&mut self, at: usize) -> &Item {
            &self.x[at]
        }
    }
    

    在上述情况下,Context.get 可以获取对self 的不可变引用,因为它不会改变任何内容。此外,如果您想允许Context.get 的调用者修改引用的项目,您将返回&amp;mut Item 而不是&amp;Item

    impl Context {
        fn get(&mut self, at: usize) -> &mut Item {
            &mut self.x[at]
        }
    }
    

    编辑:正如 @apemanzilla 在 cmets 中有用的注释,如果您希望 Context.get 在 at 返回 Item 的单独副本,您还可以让 Item 实现 Clone 特征:

    #[derive(Clone)]
    struct Item {
        value: String,
    }
    
    impl Context {
        fn get(&mut self, at: usize) -> Item {
            self.x[at].clone()
        }
    

    虽然更改返回的 Item 不会修改 self.x 中包含的 Item;这可能是也可能不是你想要的。

    【讨论】:

    • 我还要添加一条关于将 CloneCopy 特征用于小类型的注释。
    • 这是完美的,谢谢。什么是首选:克隆某物,或对它进行不可变的借用。请注意,在上下文中项目不会被修改。
    • @flooblebit 克隆可能很昂贵。如果您的意图是“我想要一个单独的副本,我可以在不更改原始文件的情况下修改它”,那么您应该克隆。如果你不改变原来的,更喜欢不可变的参考;如果您要更改原件,请选择可变参考。
    猜你喜欢
    • 2023-01-10
    • 2022-06-11
    • 2018-01-29
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    相关资源
    最近更新 更多