我有一个带有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
内的值移到了本地范围内,这意味着当方法返回时它将被删除;但是,由于该结构的寿命超过了方法调用的时间,因此该值仍可在其他位置访问,这将在释放错误后产生 use 错误。
由于我想使用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
物品本身,我真的没有追索权吗?
答案 0 :(得分:4)
我不清楚您要达到的目标,但是我可以提供一些可行的选择。
如果只想返回对字符串的引用而不更改Cell
中的任何内容,则应该从&str
返回String
而不是match_me()
。除了返回类型外,在第一个示例中,您只需要对match_me()
进行少量更改:
fn match_me(&self) -> &str {
match &self.data {
Some(x) => x,
None => "match failed",
}
}
其余代码可以保持不变。
如果要将字符串移出结构,则需要接收self
作为可变引用:
fn match_me(&mut self) -> String {
match self.data.take() {
Some(x) => x,
None => "match failed".to_owned(),
}
}
这将在调用函数后在None
中保留self.data
,因为我们正在移出字符串并将所有权转移回调用者。
最后,如果出于某种原因您确实需要共享字符串所有权,则还可以使用引用计数指针:
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()),
}
}
}
与其他选项相比,这非常不常见,您的问题中没有任何内容暗示您实际上需要此功能,因此出于完整性考虑,我仅将其包括在内。
我最好的猜测是您实际上想要第一个选择。
答案 1 :(得分:0)
如果您想返回&String
并避免使用clone
,我想扩展Sven Marnach的答案并提出另一种选择
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();
...
}