rust uprap_or_else返回引用

dl5txlt9  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(148)

我在一段动态编程中遇到了这样的情况,我要么想得到预先计算的结果,要么调用一个函数来计算这些结果。
总之就是这种情况

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中做到这一点的正确方法是什么?

vcirk6k6

vcirk6k61#

您不能返回对本地值的引用(在您的示例中为unwrap_or_else回调),因为当删除该本地值时,引用将失效。
你可以克隆从map中得到的值,但这通常不是最有效的方法,而且这个值甚至可能是不可克隆的。
这是Cow的一个使用案例:

use std::borrow::Cow;

for i in some_values {
   let result = previous_results
       .get(i)
       .map(Cow::Borrowed)
       .unwrap_or_else(|| Cow::Owned(calculate_results(i)));
}

你或多或少地使用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。

dbf7pr2w

dbf7pr2w2#

@Rodrigo已经用正确的方法回答了我的问题,但是我有点困惑魔术Cow在做什么来解决我的问题,所以我想为其他可能也困惑的人澄清一下。
我的问题的关键是.get返回对HashMap中的一个元素的引用,但是unwrap_or_else调用的函数需要返回一个拥有的值,否则一旦我们超出匿名函数的作用域,它就无效了。
因此,在@rodrigo的答案中隐藏的解决方案是在get之后调用的map,它可以用来将get返回的任何内容转换为一个拥有值,这样unwrap_or_else就可以返回一个拥有值,问题就解决了。
Cow有帮助,因为克隆.get返回的值不是最有效的,除非你以后确实需要一个副本。所以Cow抽象了所有权,让.getunwrap_or_else返回相同的类型,而不必克隆任何东西。
@rodrigo的答案应该仍然是公认的答案,因为它正确地解决了问题,但我想提供更多的背景,因为我不太确定所有权是如何解决的。

相关问题