如何从Option :: unwrap_or返回一个新的struct?

6
我有一个HashMap,它使用字符作为键,结构体作为值。
HashMap的get()方法经常会被调用,但传入的键不在HashMap中,因此我想在返回的Option上使用unwrap_or()来创建一个默认的struct值。然而,当我尝试这样做时,编译器会抛出以下错误(其中temp是我试图返回的默认值):
lib.rs:51:4: 51:8 error: `temp` does not live long enough

这是一个小的复现示例:

struct Sample {
    thing: i32
}

fn do_stuff() {
    let map = HashMap::<char, Sample>::new();

    let sample = map.get(&'a').unwrap_or({
        let temp = Sample {
            thing : 0
        };
        &temp
    });
}

我有两个问题:

  1. 是否有方法让 temp 绑定的生命周期更长?
  2. 在使用选项时,是否有更好的方法来回退到默认的 结构
2个回答

5
针对您的具体情况,您可以按照以下方式操作:
use std::collections::HashMap;
struct Sample {
    thing : i32
}

fn main() {
    let map = HashMap::<char, Sample>::new();
    let temp = Sample { thing : 0 };
    let sample = map.get(&'a').unwrap_or(&temp);
}

通常,您可能需要更像这样的内容:
use std::collections::HashMap;
#[derive(Clone)]
struct Sample {
    thing : i32
}

fn get_sample(map: &HashMap<char, Sample>) -> Sample
{
    map.get(&'a').cloned().unwrap_or_else(|| {
        Sample { thing : 0 }
    })
}

如果您真的想有条件地初始化并获取本地变量的地址,这是可能的,但不能使用 unwrap_orunwrap_or_else 来编写:

use std::collections::HashMap;
struct Sample {
    thing : i32
}

fn main() {
    let map = HashMap::<char, Sample>::new();
    let temp;
    let sample = match map.get(&'a') {
        Some(sample) => sample,
        None => {
            temp = Sample { thing : 0 };
            &temp
        }
    };
}

不知怎么的,我错过了像#3中所做的那样提前声明绑定的方法。在Rust书籍或其他任何地方,我都没有看到过提前声明的用法。谢谢! - Ian Andrews

2
请注意,您的问题显示您有一个根本的误解:

如何返回新结构体

但是你的代码却这样写:

&temp

这是对结构体的引用。问题在于,您的结构体仅在传递给 unwrap_or 的块的持续时间内存在。一旦块结束,任何未从块中返回的变量都会被删除,使对它们的任何引用无效。

有没有办法让临时绑定变量的生命周期更长?

有一种方法可以延长绑定变量的生命周期:移动代码中的位置。如果将变量的创建提前,其生命周期就会提前开始。这就是为什么Eli Friedman的第一个解决方案有效的原因。
如果您将代码更改为返回一个结构体而不是引用,则可以解释第二个解决方案的工作原理,并更好地匹配您对问题的建模方式。但是,您并不总是能够便宜地从引用转换为非引用,有时甚至是不可能的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接