【问题标题】:Why does Option<i32> lose mutability inside matched pattern?为什么 Option<i32> 在匹配模式中失去可变性?
【发布时间】:2020-06-22 15:14:51
【问题描述】:

我想将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);
}

playground

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

【问题讨论】:

    标签: rust pattern-matching mutability


    【解决方案1】:

    Shepmaster's answermcarton's answer 很好地解释了您的 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)"
    }
    

    playground

    另见:

    【讨论】:

      【解决方案2】:

      当您将my_id 的类型替换为非Copy 类型时,问题变得很明显:

      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),
                  _ => (),
              }
          }
      }
      
      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
      

      确实Some(mut id) 与引用不匹配:您刚刚复制了该字段。你真正想要的是匹配&amp;mut self.my_id,它不需要mut 在模式中:

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

      【讨论】:

        【解决方案3】:

        是和不是。通过使用Some(mut id),您声明id 应该是i32。因为i32 实现了Copy,所以生成了存储在self 中的值的可变副本,然后由read 修改。 self 中的值绝不会被修改。

        直接的解决方法是参考:

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

        这更习惯用if let

        if let Some(id) = &mut self.my_id {
            read(id);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-03-20
          • 2021-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-14
          • 2021-12-28
          相关资源
          最近更新 更多