如何将 `Option<&mut ...>` 传递给多个函数调用而不会导致移动错误?

How to pass `Option<&mut ...>` to multiple function calls without causing move errors?

既然可以传递对向量的可变引用(而不会引起移动),那么 Option<reference> 如何在不引起借用检查错误的情况下多次传递给函数?

这个简单的例子只是展示了当 Option<&mut Vec<usize>> 被多次传递给一个函数时会发生什么:

fn maybe_push(mut v_option: Option<&mut Vec<usize>>) -> usize {
    let mut c = 0;
    if let Some(ref mut v) = v_option.as_mut() {
        for i in 0..10 {
            v.push(i);
            c += i;
        }
    }

    return c;
}

fn maybe_push_multi(v_option: Option<&mut Vec<usize>>) -> usize {
    let mut c = 0;
    c += maybe_push(v_option);
    c += maybe_push(v_option);
    c += maybe_push(None);
    return c;
}

fn main() {
    let mut v: Vec<usize> = vec![];
    let v_option = Some(&mut v);
    println!("{}", maybe_push_multi(v_option));
}

(Playground)

报错:

error[E0382]: use of moved value: `v_option`
  --> <anon>:17:21
   |
16 |     c += maybe_push(v_option);
   |                     -------- value moved here
17 |     c += maybe_push(v_option);
   |                     ^^^^^^^^ value used here after move
   |
   = note: move occurs because `v_option` has type `std::option::Option<&mut std::vec::Vec<usize>>`, which does not implement the `Copy` trait

如果您不想将 Option 移入函数中,您也可以通过引用传递它。

fn maybe_push(mut v_option: &mut Option<&mut Vec<usize>>) -> usize

// ...

maybe_push_twice(&mut v_option);

然后替换:

maybe_push(None);

与:

maybe_push(&mut None);

您可以使用 match 表达式解构 Option,然后为函数的每次调用创建一个新的 Optionmaybe_push():

fn maybe_push_twice(v_option: Option<&mut Vec<usize>>) -> usize {
    let mut c = 0;
    match v_option {
        Some(v) => {
            c += maybe_push(Some(v));
            c += maybe_push(Some(v));
        }
        None => {
            c += maybe_push(None);
            c += maybe_push(None);        
        }
    };
    return c;
}

这里有一个更方便的方法:

fn maybe_push_twice(mut v_option: Option<&mut Vec<usize>>) -> usize {
    let mut c = 0;
    c += maybe_push(v_option.as_mut().map(|x| &mut **x));
    c += maybe_push(v_option);
    return c;
}

您可以使用特征而不是宏:

trait RefMut<T> {
    fn ref_mut(&mut self) -> Option<&mut T>;
}

impl<'t, T> RefMut<T> for Option<&'t mut T>{
    #[inline]
    fn ref_mut(&mut self) -> Option<&mut T>{
        self.as_mut().map(|x| &mut**x)
    }
}

fn maybe_push_twice(mut v_option: Option<&mut Vec<usize>>) -> usize {
    let mut c = 0;
    c += maybe_push(v_option.ref_mut());
    c += maybe_push(v_option);
    return c;
}