我在一段动态编程中遇到了这样的情况,我要么想得到预先计算的结果,要么调用一个函数来计算这些结果。
总之就是这种情况
let previous_results HashMap<String, Result> = HashMap::new();
for i in some_values {
let result = previous_results.get(i).unwrap_or_else(|| calculate_results(i))
}
rust编译器公正地抱怨函数调用,它说
expected reference `&HashMap<std::string::String, Result>`
found struct `HashMap<std::string::String, Result>`
这是因为.get
通常返回一个对对象的引用,而不是实际的对象,但是函数返回的是一个实际的对象。
let result = previous_results.get(i).unwrap_or_else(|| &calculate_results(i))
注意函数调用前面的&
。但这也是一个问题,因为一旦匿名函数返回,对匿名函数范围内的内容的引用将毫无意义。
cannot return reference to temporary value
returns a reference to data owned by the current function
我在这里错过了什么?在rust中做到这一点的正确方法是什么?
2条答案
按热度按时间vcirk6k61#
您不能返回对本地值的引用(在您的示例中为
unwrap_or_else
回调),因为当删除该本地值时,引用将失效。你可以克隆从map中得到的值,但这通常不是最有效的方法,而且这个值甚至可能是不可克隆的。
这是
Cow
的一个使用案例:你或多或少地使用
result
,因为它实现了Deref<Result>
。但是记住里面的值可能是从map借用的,所以Cow<'_, Result>
的值保持了map的借用。有趣的是,虽然名称
Cow
代表 Clone-On-Write,但在您需要 Owned_Or_Borrowed 时,经常会用到它。Cow
的主要缺点是它要求值为ToOwned
,这基本上意味着实现Clone
,因为名称中有C
。如果您的Result
类型不是Clone
,我认为目前在std
中没有解决方案,但很容易实现您自己的解决方案。或者使用可用板条箱,例如X1 E1 F1 X。dbf7pr2w2#
@Rodrigo已经用正确的方法回答了我的问题,但是我有点困惑魔术
Cow
在做什么来解决我的问题,所以我想为其他可能也困惑的人澄清一下。我的问题的关键是
.get
返回对HashMap中的一个元素的引用,但是unwrap_or_else
调用的函数需要返回一个拥有的值,否则一旦我们超出匿名函数的作用域,它就无效了。因此,在@rodrigo的答案中隐藏的解决方案是在
get
之后调用的map
,它可以用来将get
返回的任何内容转换为一个拥有值,这样unwrap_or_else
就可以返回一个拥有值,问题就解决了。Cow
有帮助,因为克隆.get
返回的值不是最有效的,除非你以后确实需要一个副本。所以Cow抽象了所有权,让.get
和unwrap_or_else
返回相同的类型,而不必克隆任何东西。@rodrigo的答案应该仍然是公认的答案,因为它正确地解决了问题,但我想提供更多的背景,因为我不太确定所有权是如何解决的。