【问题标题】:Rust "Types differ in mutability"Rust“类型的可变性不同”
【发布时间】:2020-06-02 18:08:46
【问题描述】:

我正在尝试从向量中删除一个元素(如果它存在于其中):

use std::collections::HashMap;

fn test(map: HashMap<String, Vec<String>>, department: String, employee: String) {
    let &mut list = map.get(&department).unwrap();
    let index = list.iter().position(|x| x == &employee);
    match index {
        Some(i) => {
            list.remove(i);
        },
        None => {
            println!("No records of {} in {}!", &employee, &department);
        },
    }
}

我收到此错误:

error[E0308]: mismatched types
 --> src/lib.rs:4:9
  |
4 |     let &mut list = map.get(&department).unwrap();
  |         ^^^^^^^^^   ----------------------------- this expression has type `&std::vec::Vec<std::string::String>`
  |         |
  |         types differ in mutability
  |
  = note:      expected reference `&std::vec::Vec<std::string::String>`
          found mutable reference `&mut _`

Playground

我以为我理解错误的含义(第 170 行的 RHS 返回对向量的不可变引用),但我不太确定如何解决它。如果尝试这样的事情:

let mut list = map.get(&department).unwrap();
let index = list.iter().position(|x| x == &employee);
match index {
    Some(i) => {
        list.remove(i);
    },
    ...
}

然后我得到

error[E0596]: cannot borrow `*list` as mutable, as it is behind a `&` reference
 --> src/lib.rs:8:13
  |
4 |     let mut list = map.get(&department).unwrap();
  |         -------- help: consider changing this to be a mutable reference: `&mut std::vec::Vec<std::string::String>`
...
8 |             list.remove(i);
  |             ^^^^ `list` is a `&` reference, so the data it refers to cannot be borrowed as mutable

Playground

这些错误对我来说似乎是一种循环,这让我觉得我需要重新考虑我的设计。我该如何解决这个问题?

【问题讨论】:

    标签: rust


    【解决方案1】:

    get 返回一个不可变的Option&lt;&amp;V&gt;,它不允许你调用.remove(i)。使用get_mut 获得可变的Option&lt;&amp;mut V&gt;。调用它要求地图本身是可变的,这表明我们正在做正确的事情。

    use std::collections::HashMap;
    
    fn test(map: &mut HashMap<String, Vec<String>>, department: String, employee: String) {
        //       ^^^^ 
        let list = map.get_mut(&department).unwrap();
        //             ^^^^^^^
        let index = list.iter().position(|x| x == &employee);
        match index {
            Some(i) => {
                list.remove(i);
            },
            None => {
                println!("No records of {} in {}!", &employee, &department);
            },
        }
    }
    

    Playground

    【讨论】:

    • @cloudy_eclispse 请注意,您可以使用Vec::retain 来简化position/remove 舞蹈。见Removing elements from a Vec based on some condition
    • @trentcl :现在仔细查看retain(),虽然这对于删除元素很好,但理想情况下,我想保留如果结果为无时我会显示的错误消息。有没有一种巧妙的方法来做到这一点?
    • @cloudy_eclispse 不幸的是不容易,不。您可以在每晚使用drain_filter(如果它返回任何项目,则将它们删除;否则,打印消息)但在稳定时,此答案可能是您的最佳选择。
    猜你喜欢
    • 2021-04-23
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 2019-06-12
    • 2019-12-20
    相关资源
    最近更新 更多