首页 > 解决方案 > “无法移出借来的内容”错误的根源是什么?

问题描述

我一直不明白为什么我会收到 Rust 错误“无法移出借来的内容”。

use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use std::vec::Vec;

pub struct user_type {
    pub name: String,
    pub ilist: Vec<i32>,
    pub user_type_list: VecDeque<Option<Rc<RefCell<user_type>>>>,
    pub parent: Option<Rc<RefCell<user_type>>>,
}

impl user_type {
    pub fn new(name: String) -> Self {
        user_type {
            name: name.clone(),
            ilist: Vec::new(),
            user_type_list: VecDeque::new(),
            parent: Option::None,
        }
    }

    pub fn to_string(&self) -> String {
        let mut result: String = String::new();

        result += "name is ";
        result += &self.name;

        let n = self.user_type_list.len();

        for iter in &self.user_type_list {
            match iter {
                Some(ref x) => {
                    let temp = x.into_inner();
                    let temp2 = temp.to_string();
                    result += &temp2[..];
                }
                None => panic!("to_string"),
            }
            result += "\n";
        }

        result
    }
}

完整的错误信息是:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:34:32
   |
34 |                     let temp = x.into_inner();
   |                                ^ cannot move out of borrowed content

这种错误的根源是什么?

标签: rust

解决方案


仔细看这段代码:

for iter in &self.user_type_list {
    match iter {
        Some(ref x) => {
            let temp = x.into_inner();
            let temp2 = temp.to_string();
            result += &temp2[..];
        }
        None => panic!("to_string"),
    }
    result += "\n";
}

在这里,您正在迭代&self.user_type_list,因此类型iter实际上是对包含值的引用:&Option<Rc<RefCell<user_type>>>。这很好,因为您不想拥有容器或其值的所有权。

然后你匹配iterSome(ref x). 较旧的编译器版本会失败,因为您将引用匹配到非引用,但如果需要,新编译器会像匹配 aOption<&T>而不是 a一样&Option<T>Some(x) =>这很方便,并且意味着您可以只编写x类型&Rc<RefCell<user_type>>而不是类型&&Rc<..>(这并不重要,自动取消引用将使它们等效)。

现在你x.into_inner()用 a打电话,&Rc<RefCell<..>>这永远不会奏效。看起来您想要获得RefCell不需要tempRc工具,Deref因此您可以免费获得。相反,编译器认为您正在调用RefCell::into_inner(self) -> T,但此函数使用self来获取包含的值。你不拥有它,你只是借来的。这就是错误消息的含义:您正在尝试消费(移出)和您不拥有的对象(借用)。

你真正想要的只是借user_type足够的电话to_string()

Some(x) => { 
    let temp = x.borrow().to_string();
    result += &temp;
}

推荐阅读