本地拥有的参考资料被认为是借来的
Locally owned reference considered borrowed
我有一个带有 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
内部的值移动到局部范围内,这意味着它会在方法 returns 时被删除;但是,由于该结构比方法调用还长,该值仍可在其他地方访问,这将产生 use after free 错误。
因为我想使用 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
物品本身,我真的别无选择吗?
我不清楚你想要达到什么目的,但我可以提供一些可行的选择。
如果您只想 return 对字符串的引用而不更改 Cell
中的任何内容,您应该 return &str
而不是 String
来自 match_me()
。除了 return 类型之外,您只需要对第一个示例中的 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(),
}
}
这将在调用该函数后在 self.data
中留下一个 None
,因为我们将字符串移出并将所有权转移回调用者。
最后,如果出于某种原因你确实需要字符串的共享所有权,你也可以使用引用计数指针:
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()),
}
}
}
这比其他选项更不常见,而且您的问题中没有任何内容暗示您确实需要它,所以我只是为了完整性才包含它。
我最好的猜测是你实际上想要第一个选项。
如果您想 return &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();
...
}
我有一个带有 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
内部的值移动到局部范围内,这意味着它会在方法 returns 时被删除;但是,由于该结构比方法调用还长,该值仍可在其他地方访问,这将产生 use after free 错误。
因为我想使用 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
物品本身,我真的别无选择吗?
我不清楚你想要达到什么目的,但我可以提供一些可行的选择。
如果您只想 return 对字符串的引用而不更改
Cell
中的任何内容,您应该 return&str
而不是String
来自match_me()
。除了 return 类型之外,您只需要对第一个示例中的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(), } }
这将在调用该函数后在
self.data
中留下一个None
,因为我们将字符串移出并将所有权转移回调用者。最后,如果出于某种原因你确实需要字符串的共享所有权,你也可以使用引用计数指针:
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()), } } }
这比其他选项更不常见,而且您的问题中没有任何内容暗示您确实需要它,所以我只是为了完整性才包含它。
我最好的猜测是你实际上想要第一个选项。
如果您想 return &String
并避免 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();
...
}