< 返回版块

243011068 发表于 2020-04-13 13:54

Tags:hashmap,or_insert

直接看demo

let mut map = HashMap::new();
let mut is_new = false;

map.entry(1).or_insert({
    is_new = true;
    1
});

if is_new {
    println!("is_new");
}

目的是想在map新增key的时候做一些处理,看起来很美好,编译通过了,但是多了警告 warning: value assigned to is_new is never read --> src\main.rs:133:13

纳尼?is_new明明用了啊而且控制台还打印了,当时心里还暗想难道是rust的bug?,带着疑问我在群里问了下,经过讨论最后“大头矮子”还原了真相,原来or_insert传的是值,并不是闭包,也就是我传了个表达式进去,is_new无论什么情况都会执行等于true,if is_new 就等同于if true 所以rust编译器认为is_new根本不需要才会有此警告,不得不说rust编译器真是强大,要是没这个警告我就掉坑里了,哈哈。 最后此问题解决方案可以调用or_insert_with。完美解决。

评论区

写评论
whfuyn 2020-04-20 20:25

对以下内容的回复:

这段代码里,你知道这个闭包的is_new = true;必然会被执行,但编译器不知道,如果这个闭包没有执行,那么接下来println!("{}", is_new);就读到了false

Nalleyer 2020-04-13 20:54

fn foo<F: FnOnce() -> ()>(f: F) {
    f()
}

fn bar(v: u32) {
    println!("bar {}", v);
}

fn test_c() {
    let mut is_new = false;
    foo(|| {
        is_new = true;
    });
    
    println!("{}", is_new);
    // no warning
}

fn test_d() {
    let mut is_new = false;
    bar({
        is_new = true;
        233u32
    });
    
    println!("{}", is_new);
    
    // warning
}

写了个更小的例子,是不是FnOnce捕获环境的时候认为读了is_new里面的值一次呢。

对以下内容的回复:

Nalleyer 2020-04-13 20:43

为了证明我的推测

fn test_a() {
    let mut map = HashMap::new();
    let mut is_new = false;
    
    println!("{}", is_new);

    map.entry(1).or_insert({
        is_new = true;
        1
    });

    println!("{}", is_new);

    if is_new {
        println!("emm");
    }
}

or_insert前读一下is_new也消除了warning。

对以下内容的回复:

Nalleyer 2020-04-13 20:37

我还是不解,请教一下各位。

warning: value assigned to `is_new` is never read

我能理解它是说一开始给is_newfalse没人读过。

但是换了or_insert_with如下:

fn test_b() {
    let mut map = HashMap::new();
    let mut is_new = false;

    map.entry(1).or_insert_with(|| {
        is_new = true;
        1
    });

    println!("{}", is_new);

    if is_new {
        println!("emm");
    }
}

那个false仍然没人读过,为什么就不warning了呢。

songday 2020-04-13 17:29

这个还真是一个小坑。谢谢分享

1 共 5 条评论, 1 页