为什么 Option<i32> 在匹配模式中失去可变性?

nya*_*108 3 pattern-matching mutability rust

我想将my_id,仅当存在时更改为另一个值:

fn read(id: &mut i32) {
    *id = 42;
}

struct S {
    my_id: Option<i32>,
}

impl S {
    fn run(&mut self) {
        match self.my_id {
            Some(mut id) => read(&mut id),
            _ => (),
        }
    }
}

fn main() {
    let mut s = S { my_id: 0.into() };

    s.run();

    println!("{:?}", s.my_id);
}
Run Code Online (Sandbox Code Playgroud)

操场

此代码打印Some(0),这意味着替换失败,但我不明白为什么。我是否因为模式匹配而失去了可变性?

kfe*_*v91 7

Shepmaster 的回答mcarton 的回答很好地解释了您i32是如何被复制而不是在模式匹配中被引用的。

我想补充一点,该ref关键字专门用于处理这样的情况,您需要引用而不是模式匹配中的副本:

fn read(id: &mut i32) {
    *id = 42;
}

struct S {
    my_id: Option<i32>,
}

impl S {
    fn run(&mut self) {
        match self.my_id {
            // `ref` keyword added here
            Some(ref mut id) => read(id),
            _ => (),
        }
    }
}

fn main() {
    let mut s = S { my_id: 0.into() };
    s.run();
    println!("{:?}", s.my_id); // prints "Some(42)"
}
Run Code Online (Sandbox Code Playgroud)

操场

也可以看看:


mca*_*ton 5

当您用my_id非复制类型替换类型时,问题变得明显:

fn read(_: &mut String) {}

struct S {
    my_id: Option<String>,
}

impl S {
    fn run(&mut self) {
        match self.my_id {
            Some(mut id) => read(&mut id),
            _ => (),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
error[E0507]: cannot move out of `self.my_id.0` which is behind a mutable reference
  --> src/lib.rs:9:15
   |
9  |         match self.my_id {
   |               ^^^^^^^^^^ help: consider borrowing here: `&self.my_id`
10 |             Some(mut id) => read(&mut id),
   |                  ------
   |                  |
   |                  data moved here
   |                  move occurs because `id` has type `std::string::String`, which does not implement the `Copy` trait
Run Code Online (Sandbox Code Playgroud)

Some(mut id)通过引用确实不匹配:您刚刚制作了该字段的副本。您真正想要的是匹配 on &mut self.my_id,这mut在模式中不需要:

match &mut self.my_id {
    Some(id) => read(id),
    _ => (),
}
Run Code Online (Sandbox Code Playgroud)