rust - 本地拥有的引用资料被认为是借来的

标签 rust borrow-checker borrowing lifetime-scoping

我有一个 Option<String> 的结构类型 field 。在我的可选类型的方法中,我想匹配该字段并将值提取到本地范围中。我知道我需要说服借用检查器不要删除我的结构类型中指向的内存;我不确定该怎么做。

对于上下文,这是一个明显错误的例子。

struct Cell {
    data: Option<String>,
}

impl Cell {
    fn match_me(&self) -> String {
        match self.data {
            Some(x) => x,
            None => "match failed".to_owned(),
        }
    }
}

fn main() {
    let data = Some("hello".to_owned());
    let my_cell = Cell { data };
    let result = my_cell.match_me();
    print!("{}", result);
}

这个程序显然是错误的,因为我把值移到了x里面。进入本地范围,这意味着当方法返回时它将被删除;然而,由于该结构比方法调用还长,该值仍可在其他地方访问,这会产生释放后使用错误。

因为我想使用 Some()值而不丢弃它,我想我应该引用计数它。尝试二:

use std::rc::Rc;

struct Cell {
    data: Rc<Option<Rc<String>>>,
}

impl Cell {
    fn match_me(&self) -> String {
        let local = self.data.clone();
        match *local {
            Some(x) => *Rc::clone(&x),
            None => "match failed".to_owned(),
        }
    }
}

fn main() {
    let data = Rc::new(Some(Rc::new("hello".to_owned())));
    let my_cell = Cell { data };
    let result = my_cell.match_me();
    print!("{}", result);
}

然而,尽管克隆了这些引用,我仍然遇到借用错误。

   Compiling playground v0.0.1 (file:///playground)
error[E0507]: cannot move out of borrowed content
  --> src/main.rs:10:15
   |
10 |         match *local {
   |               ^^^^^^ cannot move out of borrowed content
11 |             Some(x) => *Rc::clone(&x),
   |                  - hint: to prevent move, use `ref x` or `ref mut x`

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:11:24
   |
11 |             Some(x) => *Rc::clone(&x),
   |                        ^^^^^^^^^^^^^^ cannot move out of borrowed 
content

除了clone,我真的别无选择吗?元素本身?

Playground Link to the obviously wrong example.

Playground Link to a reference counted nightmare.

最佳答案

我不清楚您要实现的目标,但我可以提供一些可行的选项。

  1. 如果您只想返回对字符串的引用而不更改 Cell 中的任何内容,您应该返回 &str 而不是 String 来自 match_me()。除了返回类型之外,您只需要对第一个示例中的 match_me() 进行少量更改:

    fn match_me(&self) -> &str {
        match &self.data {
            Some(x) => x,
            None => "match failed",
        }
    }
    

    您的其余代码可以保持不变。

  2. 如果您想将字符串移出您的结构,您需要接收 self 作为可变引用:

    fn match_me(&mut self) -> String {
        match self.data.take() {
            Some(x) => x,
            None => "match failed".to_owned(),
        }
    }
    

    这将在调用该函数后在 self.data 中留下一个 None,因为我们将字符串移出并将所有权转移回调用者。

  3. 最后,如果出于某种原因您确实需要字符串的共享所有权,您还可以使用引用计数指针:

    struct Cell {
        data: Option<Rc<String>>,
    }
    
    impl Cell {
        fn match_me(&self) -> Rc<String> {
            match &self.data {
                Some(x) => x.clone(),
                None => Rc::new("match failed".to_owned()),
            }
        }
    }
    

    这比其他选项更不常见,而且您的问题中没有任何内容暗示您确实需要这个,所以我只是为了完整性才包含这个。

我最好的猜测是您实际上想要第一个选项。

关于rust - 本地拥有的引用资料被认为是借来的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52544921/

相关文章:

rust - 为什么分配时会得到 "temporary value dropped while borrowed",但通过函数传递时却不会?

rust - 如何为自定义结构类型实现 Mul Trait 以两种方式工作

sorting - 使用 std::collections::BinaryHeap 就地堆排序

rust - 从 HashMap 或 Vec 返回引用会导致借用超出其所在范围?

rust - Rust-从 `&str`转换为 `String`,然后使用闭包转换

rust - 整个Box都可以 move 时,Box可以 move 其内容吗?

rust - 对多个参数使用相同的生命周期有什么好处?

rust - 如何打印!一个选项<Box<struct>>?

Rust:如何返回对 Rc<RefCell<HashMap<K, V>> 值的引用?

rust - 为什么将函数移至默认特征方法会导致借入错误?