【发布时间】:2018-10-17 16:04:23
【问题描述】:
我有一个struct Foo<'a>,它是&'a str 引用的包装。我想用Foos 作为键填充HashMap。这是一段 sn-p 代码 (open it in playground):
use std::collections::HashMap;
#[derive(PartialEq, Eq, Hash)]
struct Foo<'a> {
txt: &'a str,
}
fn main() {
let a = "hello".to_string();
let a2 = Foo { txt: &a };
let b = "hello".to_string();
let b2 = Foo { txt: &b };
let mut hm = HashMap::<Foo, u32>::new();
hm.insert(a2, 42);
println!("=== {:?}", hm.get(&b2)); // prints Some(42)
println!("=== {:?}", hm.get_mut(&b2)); // prints Some(42)
{
let c = "hello".to_string();
let c2 = Foo { txt: &c };
println!("=== {:?}", hm.get(&c2)); // prints Some(42)
// println!("=== {:?}", hm.get_mut(&c2)); // does not compile. Why?
// hm.insert(c2, 101); // does not compile, but I understand why.
}
}
这段代码可以完美编译和运行,但是如果我取消注释最后两行代码,编译器会报错。更准确地说,它抱怨 c2 中的借来的值不够长。
对于最后一个 (insert),这是完全可以理解的:我不能将 c2 移动到 HashMap,它的寿命比 c2 从 c 借来的数据要长。
但是,我不明白为什么倒数第二行 (get_mut) 有同样的问题:在这种情况下,借用的数据应该只在调用 get_mut 期间是必需的,它不是移入HashMap。
更令人惊讶的是,上面的get 可以完美运行(正如我所料),并且get 和get_mut 在k 参数方面具有相同的签名......
再挖一点之后, 我用普通引用(而不是嵌入引用的结构)重现了这个问题。
use std::collections::HashMap;
fn main() {
let a = 42;
let b = 42;
let mut hm = HashMap::<&u32,u32>::new();
hm.insert(&a, 13);
println!("=== {:?}", hm.get(&&b)); // prints Some(13)
println!("=== {:?}", hm.get_mut(&&b)); // prints Some(13)
{
let c = 42;
println!("=== {:?}", hm.get(&&c)); // prints Some(13)
//println!("=== {:?}", hm.get_mut(&&c)); // does not compile. Why?
}
}
同样,取消注释最后一行会导致编译器抱怨(与上面的消息相同)。
但是,对于这个特定示例,我发现了一个有趣的解决方法:在最后一行中将 &&c 替换为 &c 解决了问题——实际上,可以在对 @987654348 的所有调用中将 && 替换为 & @ 和 get_mut。我想这与 &T 实现 Borrow<T> 有关。
我不明白在这个解决方法中究竟是什么说服了编译器做我想让它做的事情。而且我不能直接将它应用到我的原始代码中,因为我不使用 references 作为键,而是使用嵌入引用的对象,所以我无法将 && 替换为 &...
【问题讨论】:
-
我相信Why does linking lifetimes matter only with mutable references? 已经回答了这个问题。如果您不同意,请edit您的问题解释这与现有答案有何不同。否则,我们可以将其标记为已回答。
-
另外,编译器如何知道
get_mut不会将参数存储在HashMap中,只使用函数的签名?跨度> -
我不完全确定我的问题与您提到的问题相同。大多数情况下,不同之处在于,在我的例子中,只涉及对
Foo(借用类型)的不可变引用。 -
但是,您对
get_mut很清楚:区别(与get)不在于参数k,而在于self是可变的。 -
如果您的问题的答案包含“方差”一词,那么您将度过一段糟糕的时光。对于可能的回答者,我发现以下一些事实很有启发性:
&T是T的变体,&mut T在T中是不变的,HashMap<K, V>是K的变体。祝你好运!