匹配Option时`Some(&a) => a`和`Some(a) => *a`有什么区别?

What is the difference between `Some(&a) => a` and `Some(a) => *a` when matching an Option?

为什么会通过:

fn f(v: Vec<isize>) -> (Vec<isize>, isize) {
    match v.get(0) {
        Some(&a) => (v, a),
        _ => (v, 0)
    }
}

Playground

但这不是吗?:

fn f(v: Vec<isize>) -> (Vec<isize>, isize) {
    match v.get(0) {
        Some(a) => (v, *a),
        _ => (v, 0)
    }
}

Playground

error[E0505]: cannot move out of `v` because it is borrowed
 --> src/main.rs:7:21
  |
6 |     match v.get(0) {
  |           - borrow of `v` occurs here
7 |         Some(a) => (v, *a),
  |                     ^ move out of `v` occurs here

在第一个片段中,当您键入 Some(&a) 时,您没有借用 v,因为 a 被复制了。

在第二种情况下,Some(a)Option<&isize> 类型,因此它持有对 v 的引用。当您尝试移动它时,它会触发错误。如果你先复制它,然后你 return 这对,它会起作用(但是你需要 NLL feature):

#![feature(nll)]

fn main() {
    println!("{:?}", f(vec![1]))
}

fn f(v: Vec<isize>) -> (Vec<isize>, isize) {
    match v.get(0) {
        Some(a) => {
            let a = *a; // v is no more borrowed
            (v, a)
        },
        _ => (v, 0)
    }
}

Playground

借用检查器不可能是完美的,因此您经常会遇到一些稍微不一致的东西。

v.get(0) returns 对向量中元素的引用,因此您正在匹配 &isizeVec现在被火柴臂借用了。

在第一个代码片段中,您复制了 isize,因此此处没有借用 Vec。在第二个片段中,Vec 仍然是借用的,因此您不能将其移出范围。

但是,您应该考虑使用 if letunwrap_or:

fn f(v: Vec<isize>) -> (Vec<isize>, isize) {
    let a = v.get(0).cloned();
    (v, a.unwrap_or(0))
}

Playground

fn f(v: Vec<isize>) -> (Vec<isize>, isize) {
    if let Some(&a) = v.get(0) {
        (v, a)
    } else {
        (v, 0)
    }
}

Playground


另请参阅:

  • How do I not borrow an Option when matching?
  • How do I borrow a reference to what is inside an Option<T>?