`if`分支具有自有和借用值,没有let绑定
我有这个if声明,其中两个分支都必须返回一个&HashMap<..>. 在其中一个分支中,虽然我拥有一个分支,而另一个分支中HashMap我正在从对某个结构的引用访问一个。目前,我被迫let在if块外定义一个未绑定的变量来保存来自第一个分支的拥有的映射(否则它将在if块的末尾被释放并且引用将无效)。
struct Descriptor {
env: HashMap<String, String>
}
fn merge_env(_a: &HashMap<..>, _b: &HashMap<..>) -> HashMap<String, String> {
todo!()
}
fn example(d1: &Descriptor, d2: &Descriptor, feature_on: bool) {
// Can I somehow avoid having to declare this?
let holder;
let env = if feature_on {
holder = merge_env(&d1.env, &d2.env);
&holder
} else {
&d1.env
};
read_env(&env);
}
fn read_env(_env: &HashMap<String, String>) { todo!() }
操场
有没有办法避免未绑定let?也许一些包装器可以同时保存拥有和借用的价值?另外,目前的方式是惯用的吗?
回答
变量有 Rust 的范围。一旦它们的范围结束,它们就会被取消分配。因此,如果你像这样声明你的holder内部if:
if feature_on {
let holder = merge_env(&d1.env, &d2.env);
&holder
}
// holder has already been dropped at that point. It would be "use after free" error to use it here
在if块外使用它是不可能的,因为它会在那个时候被丢弃。因此,您必须确保拥有的对象存在足够长的时间。
可能的解决方案之一是您已经完成的操作 - 通过在if您保证持有者实例不会被解除分配之前移动拥有变量,从而避免在免费错误后使用。
另一种解决方案是使用 enum std::borrow::Cow,它有两个变体Cow::Borrowed——用于保存引用和Cow::Owned保存实际实例。这完全适合您的用例:
if feature_on {
let holder = merge_env(&d1.env, &d2.env);
&holder
}
// holder has already been dropped at that point. It would be "use after free" error to use it here