如何在没有Rust移动第一次访问的情况下访问选项中的向量?
fn maybe_push(v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(v) = v_option {
for i in 0..10 {
v.push(i);
c += i;
}
} else {
for i in 0..10 {
c += i;
}
}
// second access, fails
if let Some(v) = v_option {
for i in 10..20 {
v.push(i);
c += i;
}
} else {
for i in 10..20 {
c += i;
}
}
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
println!("{}", maybe_push(Some(&mut v)));
println!("{}", maybe_push(None));
println!("{:?}", v);
}
这给出了错误:
error[E0382]: use of partially moved value: `v_option`
--> src/main.rs:16:22
|
4 | if let Some(v) = v_option {
| - value moved here
...
16 | if let Some(v) = v_option {
| ^^^^^^^^ value used here after move
使用已建议的if let Some(ref mut v) = v_option {
也失败了:
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::Some).0` as mutable
--> src/main.rs:4:21
|
4 | if let Some(ref mut v) = v_option {
| ^^^^^^^^^
error: cannot borrow immutable anonymous field `(v_option:std::prelude::v1::Some).0` as mutable
--> src/main.rs:17:21
|
17 | if let Some(ref mut v) = v_option {
| ^^^^^^^^^
答案 0 :(得分:6)
按值匹配将值移动到模式变量中。移动使原始值不可用,除了实现Copy
特征的非常简单的对象,例如数字。与C中的指针不同,可变引用不可复制,这可以在以下不编译的示例中看到:
let mut v = vec![1, 2, 3];
let rv = &mut v; // mutable reference to v
{
// move rv to r1, r1 now becomes the sole mutable reference to v
let r1 = rv;
r1.push(4);
}
{
let r2 = rv; // error: rv was already moved to r1
r2.push(5);
}
Rust拒绝上述内容,因为它强制执行禁止对对象进行多个可变引用的一般规则。尽管这个特定的代码片段是安全的,但允许同时对同一个对象进行多个可变引用会使编写Rust明确设计用于防止的不安全程序变得容易,例如,包含多线程代码中的数据争用的那些,或通过无效的迭代器访问数据的那些。因此,作业let r1 = rv
只能移动 rv
对r1
的引用,不允许现在引用移动变量let r2 = rv
的{{1}}语句}。
要修复代码,我们必须为引用创建单独的引用。这将创建对原始引用的两个不同的可变引用,而不是将原始可变引用移动到内部范围中:
rv
let mut v = vec![1, 2, 3];
let mut rv = &mut v;
{
// rr1 is a *new* mutable reference to rv - no move is performed
let rr1 = &mut rv;
rr1.push(4);
}
{
// rr2 is a *separate* new mutable reference to rv - also no move
let rr2 = &mut rv;
rr2.push(5);
}
调用的语法与push
和r1.push
相同,因为Rust的rr1.push
运算符会自动取消引用任意数量的引用。
要返回问题中的示例,.
中对Vec<usize>
的引用与上面的Option
引用类似,并使用v
模式进行匹配引用Some(v)
模式变量。
要修复它,必须按照上面的示例更改模式,以指定引用的变量,该变量本身就是一个引用。这是使用v
语法实现的。如上所述,在if let Some(ref mut v)
声明必须更改为可变的情况下,此修复还要求rv
是可变的。通过这两个更改,代码编译:
Option
另一种可能性是使用fn maybe_push(mut v_option: Option<&mut Vec<usize>>) -> usize {
let mut c = 0;
if let Some(ref mut v) = v_option {
for i in 0..10 {
v.push(i);
c += i;
}
} else {
for i in 0..10 {
c += i;
}
}
if let Some(ref mut v) = v_option {
for i in 10..20 {
v.push(i);
c += i;
}
} else {
for i in 10..20 {
c += i;
}
}
return c;
}
fn main() {
let mut v: Vec<usize> = vec![];
println!("{}", maybe_push(Some(&mut v)));
println!("{}", maybe_push(None));
println!("{:?}", v);
}
方法将选项内容作为对先前内容的可变引用返回。这在概念上等同于第一个代码段中从as_mut()
到let r1 = rv
的更改,并允许使用let rr1 = &mut rv
模式,其中if let Some(v)
仍然是对mutable的引用参考向量。这也要求v
被声明为可变。