Rust 如何在';选项';?

Rust 如何在';选项';?,rust,borrow-checker,Rust,Borrow Checker,如何访问选项中的向量而不在第一次访问时移动它 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 {

如何访问选项中的向量而不在第一次访问时移动它

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);
}
如果已建议的某些(ref mut v)=v_选项{也失败,则使用

错误:无法借用不可变匿名字段“”(v_选项:std::prelude::v1::Some)。0`作为可变字段
-->src/main.rs:4:21
|
4 |如果让一些(参考mut v)=v|u选项{
|                     ^^^^^^^^^
错误:无法借用不可变匿名字段“”(v_选项:std::prelude::v1::Some)。0`作为可变字段
-->src/main.rs:17:21
|
17 |如果让一些(参考mut v)=v|u选项{
|                     ^^^^^^^^^
按值匹配将值移动到模式变量中。移动会使原始值不可用,但实现
复制
特性的非常简单的对象除外,例如数字。与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明确设计用于防止的不安全程序变得容易,例如t在多线程代码中不包含数据争用,或通过无效迭代器访问数据的争用。因此赋值
let r1=rv
只能将
rv
引用移动到
r1
,不允许
let r2=rv
语句,该语句现在引用移动的变量
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
rr1.push
相同,因为Rust的
操作符将自动取消引用任意数量的引用

要从问题返回示例,在
选项中对
Vec
的引用类似于上面的
v
引用,使用
Some(v)
模式匹配它会将引用移动到
v
模式变量中

要修复它,必须像上面的例子那样更改模式,以指定一个变量,该变量引用的值本身就是一个引用。这是通过使用
if let Some(ref mut v)实现的
语法。如上所述,如果必须将
rv
声明更改为可变,此修复程序还要求
选项
是可变的。通过这两个更改,代码将编译:

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);
}
fn可能推送(mut v_选项:选项)->usize{
设mutc=0;
如果让一些(参考mut v)=v_选项{
因为我在0..10{
v、 推(i);
c+=i;
}
}否则{
因为我在0..10{
c+=i;
}
}
如果让一些(参考mut v)=v_选项{
因为我在10…20{
v、 推(i);
c+=i;
}
}否则{
因为我在10…20{
c+=i;
}
}
返回c;
}
fn main(){
让mut v:Vec=Vec![];
println!(“{}”,可能是推(一些(&mut v));
println!(“{}”,可能是推(无));
println!(“{:?}”,v);
}

另一种可能是使用
as_mut()
方法返回选项内容,作为对以前内容的可变引用。这在概念上等同于在第一个代码段中从
let r1=rv
更改为
let rr1=&mut rv
,并且允许使用
,如果让一些(v)
模式,其中
v
仍然是对向量的可变引用。这也要求
v_选项
声明为可变。

在书中:(非常简洁)@Shepmaster Nice alternative,谢谢。我现在已经更新了答案,将其包括在内,并补充解释了为什么最初的举措不起作用。