0

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

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

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 链接到明显错误的示例。

Playground 链接到引用计数的噩梦。

4

2 回答 2

4

我不清楚您要达到什么目标,但我可以提供一些可行的选择。

  1. 如果您只想返回对字符串的引用而不更改 中的任何内容Cell,则应返回&str而不是Stringfrom 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(),
        }
    }
    

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

  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()),
            }
        }
    }
    

    这比其他选项少见得多,并且您的问题中没有任何内容暗示您确实需要这个,所以我只是为了完整性而将其包括在内。

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

于 2018-09-27T21:45:44.300 回答
0

&String如果您想返回并避免,我想扩展 Sven Marnach 的答案并提出另一种选择clone

impl Cell {
    // it is better to use `Result` type in case when an error may be occurred
    fn match_me(&self) -> Result<&String, &'static str> {
        match self.data {
            // `ref` provides to bind a reference to a variable
            // cel: &String 
            Some(ref cel) => Ok(cel),
            None => Err("match failed"),
        }
    }
}

fn main() {
    ...
    // add unwrap to get a value
    let result = my_cell.match_me().unwrap();
    ...
}
于 2018-09-27T22:03:39.407 回答