< 返回版块

DaemonW 发表于 2020-04-06 10:08

Tags:rust;HashMap

最近开始学习Rust,用HashMap写demo时,遇到一个奇怪的问题,想了好久都想不明白,请您指教:

原代码如下:

use std::collections::HashMap;

fn main() {
    Solution::test();
    Solution::length_of_longest_substring(String::from("adekaehgo"));
}

struct Solution {}

impl Solution {
    pub fn length_of_longest_substring(s: String) -> i32 {
        let mut start: usize = 0;
        let mut end: usize = 0;
        let mut len = 1;
        let mut max_len = 1;
        let mut map: HashMap<u8, usize> = HashMap::new();
        let mut n: usize = 0;
        let arr = s.as_bytes();
        for e in arr {
            match map.get(e) {
                Some(v) => {
                    //repeat
                    println!(
                        "repeat chat = ({},{}),start at {}, end at = {}, len = {}",
                        e, v, start, end, len
                    );
                    start = *v + 1;
                    println!("start = {}", start);
                    end = n;
                    len = end - start;
                    map.insert(*e, n);
                    Solution::remove_before(arr, v, &mut map);
                }
                None => {
                    //not repeat
                    end += 1;
                    map.insert(*e, n);
                    len = end - start;
                    if len > max_len {
                        max_len = len;
                    }
                }
            }
            n += 1;
        }
        return max_len as i32;
    }

    fn remove_before(arr: &[u8], i: &usize, hashmap: &mut HashMap<u8, usize>) {
        let mut n = 0;
        while n < *i {
            let c = arr[n];
            hashmap.remove(&c);
            n += 1;
        }
    }

    pub fn test() {
        let mut map: HashMap<u8, usize> = HashMap::new();
        let mut n = 0;
        let arr = [3; 3];
        for e in &arr {
            map.insert(*e, 564);
            map.insert(*e, 2);
            match map.get(e) {
                Some(a) => {
                    println!("{}", a);
                    //map.remove("tset");
                    map.insert(*e, 45);
                    Solution::remove_before(&arr, &2, &mut map)
                }
                None => (),
            }
            //map.insert(*e, 78);
            n += 1;
        }
    }
}

其中length_of_longest_substring为我写的解决问题的函数,但是却一直编译报错如下:

error[E0502]: cannot borrow `map` as mutable because it is also borrowed as immutable
  --> src/main.rs:31:21
   |
20 |             match map.get(e) {
   |                   --- immutable borrow occurs here
...
31 |                     map.insert(*e, n);
   |                     ^^^^^^^^^^^^^^^^^ mutable borrow occurs here
32 |                     Solution::remove_before(arr, v, &mut map);
   |                                                  - immutable borrow later used here

无奈,我仿照这个函数写了一个test函数,核心代码与报错的函数逻辑相似,但是却可以编辑成功并执行,想了好久都不明白,请指教

评论区

写评论
leptonyu 2020-04-09 18:27

let vv = *v; 这里是 vv用的copy 语义,产生了新的变量。 由于nll优化,变量v在此后不被使用,因此编译器判断其作用域提前结束。 后续可变引用可以允许执行。

这种地方可以考虑使用hashmap::entry更容易理解

作者 DaemonW 2020-04-06 11:52

对以下内容的回复:

嗯嗯,就像之前的前辈说的,Some(v)中的v实际上持有了map的引用,改变一下就好了

fn main() {
    let mut map: HashMap<u8, usize> = HashMap::new();
    let key = 233u8;
    match map.get(&key) {
        Some(v) => {
            let index = *v;//添加这句,解除对map的不可变引用
            map.insert(1u8, 2usize);
            //remove(&mut map, &key, v); 这样就不行
            remove(&mut map, &key, &index);
        },
        None => ()
    }
}
Nalleyer 2020-04-06 11:05

搞了个最小例子,跟lz的问题一样,方便研究

use std::collections::HashMap;

fn remove(m: &mut HashMap<u8, usize>, k: &u8, v: &usize) {
    if *v < 1usize {
        m.remove(k);
    }
}

fn main() {
    let mut map: HashMap<u8, usize> = HashMap::new();
    let key = 233u8;
    match map.get(&key) {
        Some(v) => {
            map.insert(1u8, 2usize);
            //remove(&mut map, &key, v); 这样就不行
            remove(&mut map, &key, &0usize);
        },
        None => ()
    }
}
作者 DaemonW 2020-04-06 11:04

对以下内容的回复:

好的,明白了一些,非常感谢您的帮助

作者 DaemonW 2020-04-06 11:03

对以下内容的回复:

非常感谢您不辞辛苦的答复,看来我还要多加学习,理解语言的细节

作者 DaemonW 2020-04-06 11:00

对以下内容的回复:

好的,谢谢您的答复,我再研究研究

solarsail 2020-04-06 10:59

我觉得按照编译器给的提示理解就可以了。提示分3段:

  1. map.get()返回的Some(v)有对map的共享引用;
  2. map.insert()需要一个对map的独占引用;
  3. 如果下面没有再使用v(对map的共享引用),那么根据NLL(大概),编译器知道这两个不冲突,所以给过了;但是这里用了v,那就得把对map的共享引用保留到这时候,那就和上面的对map的独占引用有冲突了。

我理解大概就是这么个意思。

AlephAlpha 2020-04-06 10:56

关键是 Solution::remove_before(arr, v, &mut map) 这里,v 包含了对 map 的一个不可变引用,&mut map 又是对 map 的一个可变引用,冲突了。

Nalleyer 2020-04-06 10:54

改了版能用的,虽然还没研究明白

use std::collections::HashMap;

fn main() {
    Solution::test();
    Solution::length_of_longest_substring(String::from("adekaehgo"));
}

struct Solution {}

impl Solution {
    pub fn length_of_longest_substring(s: String) -> i32 {
        let mut start: usize = 0;
        let mut end: usize = 0;
        let mut len = 1;
        let mut max_len = 1;
        let mut map: HashMap<u8, usize> = HashMap::new();
        let mut n: usize = 0;
        let arr = s.as_bytes();
        for e in arr {
            match map.get(e) {
                Some(v) => {
                    //repeat
                    println!(
                        "repeat chat = ({},{}),start at {}, end at = {}, len = {}",
                        e, v, start, end, len
                    );
                    start = *v + 1;
                    println!("start = {}", start);
                    end = n;
                    len = end - start;
                    let vv: usize = *v; // 这里在insert下面也不行
                    map.insert(*e, n);
                    Solution::remove_before(arr, vv, &mut map);
                    //Solution::remove_before(arr, *v, &mut map);  //直接这样写就不行
                }
                None => {
                    //not repeat
                    end += 1;
                    map.insert(*e, n);
                    len = end - start;
                    if len > max_len {
                        max_len = len;
                    }
                }
            }
            n += 1;
        }
        return max_len as i32;
    }

    fn remove_before(arr: &[u8], i: usize, hashmap: &mut HashMap<u8, usize>) {
        let mut n = 0;
        while n < i {
            let c = arr[n];
            hashmap.remove(&c);
            n += 1;
        }
    }

    pub fn test() {
        // 略...
    }
}
Nalleyer 2020-04-06 10:49

我也晕了,等一位大神 对以下内容的回复:

Nalleyer 2020-04-06 10:37

把test里的

Solution::remove_before(&arr, &2, &mut map)

改成

Solution::remove_before(&arr, a, &mut map)

就一样的报错了

1 共 11 条评论, 1 页