这几天学 Rust 的时候看到的一块代码给我带来了一点疑惑:

use std::collections::HashMap;

fn main() {
    let mut hashmap = HashMap::new();

    let foo = hashmap.entry("foo").or_insert(1);
    println!("foo has value {}", foo);

    *foo += 1;
    println!("foo has value {}", foo);

		println!("hashmap now store key-value pair: {:?}", hashmap);
}

在这里我定义了一个新的哈希表变量 hashmap,并使用 HashMap.entry().or_insert() 方法在检测到没有 "foo" 这个键的时候,插入键值对 "foo" = 1 ,并返回一个值,这个值可以进行解引用操作,并自增一位。

编译之后程序会输出:

$ rustc main.rs && ./main
foo has value 1
foo has value 2
hashmap now store key-value pair: {"foo": 2}

可以看到,不止 foo 的值自增了,hashmap 里的值也自增了一位。只看代码,貌似 foo 是一个指向哈希表里的值的引用。但是没有声明 mut,为什么我可以解引用并修改他的值呢,如果要修改我难道不应该用 let mut foo = ... 来声明 foo 是可写的吗?

这里其实我理解错了,其实 foo 本身已经是一个 mutable reference,查看文档,可以看到 or_insert() 返回的是一个可变引用而不是值。

Untitled

所以在此处解引用指向的是哈希表里的值而不是 foo 本身,or_insert() 方法已经传回来了一个可写的引用,foo 的类型就是一个可写的引用。而我们修改的是哈希表里的值不是 foo 自己的值,所以就不需要声明 mutable 啦。

更加直观一点,foo 其实就是下面的这个 ref_integer

fn main() {
    let mut origin_integer = 1;
    let ref_integer = &mut origin_integer;

    *ref_integer+=1;

    println!("origin_integer: {}", origin_integer);
}

ref_integer 在此处是一个可写引用,解引用之后就是在修改 origin_integer 的值,而我并不是在修改 ref_integer 存的引用,所以不需要声明 ref_integer 是可写的。