具有借用引用的显式 return 的匹配语句
Match statement with explicit return of a borrowed reference
在研究 Rust 时,我注意到一个我不太理解的行为。
我得到了这段代码,它按预期工作:
fn get_or_create_foo(v: &mut Vec<String>) -> String {
match v.get(0) {
Some(x) => return x.clone(),
None => ()
}
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap().clone()
}
fn main() {
let mut v = Vec::new();
println!("{}", get_or_create_foo(&mut v));
println!("{}", get_or_create_foo(&mut v));
}
当我更改 get_or_create_foo()
使其成为 return 借用的字符串切片时,编译器拒绝编译它。
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
Some(x) => return x,
None => ()
}
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
}
编译日志:
$ rustc --verbose src/main.rs
src/main.rs:8:5: 8:6 error: cannot borrow `*v` as mutable because it is also borrowed as immutable
src/main.rs:8 v.push("foo".to_string());
^
src/main.rs:2:11: 2:12 note: previous borrow of `*v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `*v` until the borrow ends
src/main.rs:2 match v.get(0) {
^
src/main.rs:10:2: 10:2 note: previous borrow ends here
src/main.rs:1 fn get_or_create_foo(v: &mut Vec<String>) -> &str {
...
src/main.rs:10 }
^
error: aborting due to previous error
根据我的理解,代码是有效的:一旦控制离开 match
子句,通过采取导致代码变异 v
的路径,提到的借用可能会被 returned .
我错了吗?当允许这样的代码会导致问题时,谁能举个例子?
我不太清楚,但我怀疑你的代码:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
Some(x) => return x,
None => ()
}
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
}
由编译器通过消除显式 return
翻译成具有等效语法的内容,如下所示:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
Some(x) => x,
None => {
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
},
}
}
这显然失败并出现相同的错误。这里 get
产生 Option<&String>
,因此 v
即使在 None
分支中仍然是借用的,其中没有捕获引用。
幸运的是,有一种简单的方法可以重写函数:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
if v.get(0).is_none() {
println!("creating foo");
v.push("foo".to_string());
}
v.get(0).unwrap()
}
我自己也是 Rust 新手,但我相信我可能已经找到问题的根源。
您可以检查“get”函数的类型签名here。如您所见,“获取”函数 returns 对所请求的向量成员的借用引用(包装在 Option 中)。我的猜测是编译器无法在您的情况下验证“x”无法从匹配块中“转义”。
这是一个更简单但类似的示例,来自 A 30-minute Introduction to Rust:
fn main() {
let mut v = vec![];
v.push("Hello");
let x = &v[0];
v.push("world");
println!("{}", x);
}
In Rust, the type system encodes the notion of ownership. The variable v is an owner of the vector. When we make a reference to v, we let that variable (in this case, x) borrow it for a while. Just like if you own a book, and you lend it to me, I'm borrowing the book.
So, when I try to modify the vector with the second call to push, I need to be owning it. But x is borrowing it. You can't modify something that you've lent to someone. And so Rust throws an error.
这是我的成像方式:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
let a: &str;
match v.get(0) {
Some(x) => {
a = x;
return x;
},
None => ()
}
// Now "a" is still borrowing "v" immutably!
// println!("{:?}", a);
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
}
正如我所说,我仍然是初学者,因此可能还有更多内容。我对你的代码进行了一番研究后得出了我的结论。
一个简单的重构可以解决这个问题:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
// Notice how the borrowed value is never used and
// thus can not "escape" our match block.
Some(_) => (),
_ => v.push("foo".to_string())
}
// No need to use "get" here since we are 100% sure that
// the indexed vector contains at least one item.
return &v[0];
}
您可以稍微改进 swizard 的解决方案:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
if v.is_empty() {
println!("creating foo");
v.push("foo".to_string());
}
&v[0]
}
在研究 Rust 时,我注意到一个我不太理解的行为。
我得到了这段代码,它按预期工作:
fn get_or_create_foo(v: &mut Vec<String>) -> String {
match v.get(0) {
Some(x) => return x.clone(),
None => ()
}
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap().clone()
}
fn main() {
let mut v = Vec::new();
println!("{}", get_or_create_foo(&mut v));
println!("{}", get_or_create_foo(&mut v));
}
当我更改 get_or_create_foo()
使其成为 return 借用的字符串切片时,编译器拒绝编译它。
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
Some(x) => return x,
None => ()
}
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
}
编译日志:
$ rustc --verbose src/main.rs
src/main.rs:8:5: 8:6 error: cannot borrow `*v` as mutable because it is also borrowed as immutable
src/main.rs:8 v.push("foo".to_string());
^
src/main.rs:2:11: 2:12 note: previous borrow of `*v` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `*v` until the borrow ends
src/main.rs:2 match v.get(0) {
^
src/main.rs:10:2: 10:2 note: previous borrow ends here
src/main.rs:1 fn get_or_create_foo(v: &mut Vec<String>) -> &str {
...
src/main.rs:10 }
^
error: aborting due to previous error
根据我的理解,代码是有效的:一旦控制离开 match
子句,通过采取导致代码变异 v
的路径,提到的借用可能会被 returned .
我错了吗?当允许这样的代码会导致问题时,谁能举个例子?
我不太清楚,但我怀疑你的代码:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
Some(x) => return x,
None => ()
}
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
}
由编译器通过消除显式 return
翻译成具有等效语法的内容,如下所示:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
Some(x) => x,
None => {
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
},
}
}
这显然失败并出现相同的错误。这里 get
产生 Option<&String>
,因此 v
即使在 None
分支中仍然是借用的,其中没有捕获引用。
幸运的是,有一种简单的方法可以重写函数:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
if v.get(0).is_none() {
println!("creating foo");
v.push("foo".to_string());
}
v.get(0).unwrap()
}
我自己也是 Rust 新手,但我相信我可能已经找到问题的根源。
您可以检查“get”函数的类型签名here。如您所见,“获取”函数 returns 对所请求的向量成员的借用引用(包装在 Option 中)。我的猜测是编译器无法在您的情况下验证“x”无法从匹配块中“转义”。
这是一个更简单但类似的示例,来自 A 30-minute Introduction to Rust:
fn main() { let mut v = vec![]; v.push("Hello"); let x = &v[0]; v.push("world"); println!("{}", x); }
In Rust, the type system encodes the notion of ownership. The variable v is an owner of the vector. When we make a reference to v, we let that variable (in this case, x) borrow it for a while. Just like if you own a book, and you lend it to me, I'm borrowing the book.
So, when I try to modify the vector with the second call to push, I need to be owning it. But x is borrowing it. You can't modify something that you've lent to someone. And so Rust throws an error.
这是我的成像方式:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
let a: &str;
match v.get(0) {
Some(x) => {
a = x;
return x;
},
None => ()
}
// Now "a" is still borrowing "v" immutably!
// println!("{:?}", a);
println!("creating foo");
v.push("foo".to_string());
v.get(0).unwrap()
}
正如我所说,我仍然是初学者,因此可能还有更多内容。我对你的代码进行了一番研究后得出了我的结论。
一个简单的重构可以解决这个问题:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
match v.get(0) {
// Notice how the borrowed value is never used and
// thus can not "escape" our match block.
Some(_) => (),
_ => v.push("foo".to_string())
}
// No need to use "get" here since we are 100% sure that
// the indexed vector contains at least one item.
return &v[0];
}
您可以稍微改进 swizard 的解决方案:
fn get_or_create_foo(v: &mut Vec<String>) -> &str {
if v.is_empty() {
println!("creating foo");
v.push("foo".to_string());
}
&v[0]
}