我有一个借用HashMap
的函数,我需要按键访问值。为什么键和值是通过引用而不是值?
我的简化代码:
fn print_found_so(ids: &Vec<i32>, file_ids: &HashMap<u16, String>) {
for pos in ids {
let whatever: u16 = *pos as u16;
let last_string: &String = file_ids.get(&whatever).unwrap();
println!("found: {:?}", last_string);
}
}
为什么我必须指定密钥作为参考,即file_ids.get(&whatever).unwrap()
而不是file_ids.get(whatever).unwrap()
?
据我了解,last_string
必须是&String
类型,这意味着借用字符串,因为借用了拥有的集合。是吗?
与上述类似,我认为pos
的类型为&u16
是正确的,因为它需要ids
中的借来的值吗?
答案 0 :(得分:8)
考虑将参数作为引用或值传递的语义:
作为参考:没有所有权转让。被调用函数只是借用参数。
作为值:被调用的函数取得参数的所有权,并且可能不再被调用者使用。
由于函数HashMap::get
不需要密钥的所有权来查找元素,因此选择了限制较少的传递方法:通过引用。
此外,它不返回元素的值,只返回引用。如果它返回了值,则HashMap
中的值将不再由HashMap
拥有,因此将来无法访问。
答案 1 :(得分:3)
虽然当密钥为u16
时似乎无用,但请考虑如何使用更复杂的密钥(例如String
。
在这种情况下,按值获取密钥通常意味着必须为每次查找分配和初始化新的String
,这将是昂贵的。
答案 2 :(得分:3)
TL; DR :Rust不是Java。
Rust可能具有高级构造和数据结构,但它本质上是一种低级语言,如其指导原则之一所示:你不支付你不支付的费用使用
因此,语言及其库将尽可能地尝试消除任何多余的成本,例如不必要地分配内存。
案例1:按值获取密钥。
如果密钥是String
,这意味着当您可以使用仅一次性分配的本地缓冲区时,为每次查找分配(和解除分配)内存。
案例2:按价值返回。
按值返回意味着:
后者显然效率低(复制意味着分配),前者意味着如果用户希望在另一次插入中返回值必须再次发生,这意味着查找等......并且效率也很低。
简而言之,在这种情况下,按值返回效率很低。
因此,就效率而言,Rust是最合乎逻辑的选择,并且只要实际可行,就会传递并返回值。