在下面的代码示例中:
fn default_values() -> &'static [u32] {
static VALUES: [u32; 3] = [1, 2, 3];
&VALUES
}
fn main() {
let values: [u32; 3] = [4, 5, 6];
let optional_values: Option<&[u32]> = Some(&values);
// this compiles and runs fine
let _v = optional_values.unwrap_or_else(|| default_values());
// this fails to compile
let _v = optional_values.unwrap_or_else(default_values);
}
最后一条语句无法编译为:
error[E0597]: `values` does not live long enough
--> src/main.rs:8:49
|
8 | let optional_values: Option<&[u32]> = Some(&values);
| ^^^^^^ borrowed value does not live long enough
...
12 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
我想知道:
unwrap_or_else(|| default_values())
是否是处理此问题的正确方法,或者是否有更好的模式答案 0 :(得分:5)
发生这种情况是因为default_values
实现了Fn() -> &'static [u32]
,但没有实现for<'a> Fn() -> &'a [u32]
。特质是invariant,因此您不能将“实现Fn() -> &'static [u32]
的东西强迫为”实现Fn() -> &'a [u32]
的东西”(某些'a
小于'static
),尽管从逻辑上讲,default_values
可以满足这两个条件。
在闭包中调用时,default_values()
返回一个&'static [u32]
,但是可以立即将其强制转换为&'a u32
,从而使闭包本身能够实现Fn() -> &'a [u32]
( &'a
由编译器确定的位置。
关于为什么添加as fn() -> &'static [u32]
的原因,我假设编译器可以识别出函数指针类型fn() -> &'static [u32]
能够为任何Fn() -> &'a [u32]
实现'a
。我不确定为什么它对普通的函数和闭包也不会这样做;也许将来的编译器版本可能足够聪明以允许使用原始代码。
另一种解决方案是使default_values
的类型可以实现您需要的Fn
特征:
fn default_values<'a>() -> &'a [u32] {
static VALUES: [u32; 3] = [1, 2, 3];
&VALUES
}
这里的签名不是说“这是一个返回'static
引用的函数”,而是说“这是一个可以返回任何生存期的引用的函数”。我们知道“任何生命周期的引用”都必须是'static
引用,但是编译器认为签名是不同的,因为该签名具有附加的自由度。 This change is sufficient to make your original example compile.
答案 1 :(得分:2)
闭包和直接函数调用之间没有区别:这只是类型推断的问题。
编译的闭包
let _v = optional_values.unwrap_or_else(|| default_values());
let _v = optional_values.unwrap_or_else(|| -> & [u32] {default_values()});
无法编译的封包:
let _v = unwrap_or_else(optional_values, || -> &'static [u32] {default_values()});
编译功能:
let _v = unwrap_or_else(optional_values, default_values as fn() -> &'static _);
无法编译的功能:
let _v = unwrap_or_else(optional_values, default_values);
考虑以下等效代码:
fn default_values() -> &'static [u32] {
static VALUES: [u32; 3] = [1, 2, 3];
&VALUES
}
fn unwrap_or_else<T, F>(slf: Option<T>, f: F) -> T where
F: FnOnce() -> T, {
match slf {
Some(t) => t,
None => f()
}
}
以下代码段:
fn main() {
let values: [u32; 3] = [4, 5, 6];
let optional_values: Option<&[u32]> = Some(&values);
let _v = unwrap_or_else(optional_values, || -> &'static [u32] {default_values});
// the above throws the same error of:
//let _v = unwrap_or_else(optional_values, default_values);
}
失败:
error[E0597]: `values` does not live long enough
--> src/main.rs:18:48
|
18 | let optional_values: Option<&[u32]> = Some(&values);
| ^^^^^^^
| |
| borrowed value does not live long enough
| cast requires that `values` is borrowed for `'static`
...
27 | }
| - `values` dropped here while still borrowed
从单色化方面看:假设
编译器推断T
解析为具体类型&'static [u32]
,
并假设产生的代码是这样的:
fn unwrap_or_else_u32_sl_fn_u32_sl(slf: Option<&'static [u32]>,
f: fn() -> &'static [u32]) -> &'static [u32] {
...
}
然后以上的单色化解释了错误:
slf
的值为optional_values
:寿命不足且显然不能强制转换的Option<&'a [u32]>
,因为它不满足'static
的生存期要求。
如果您写:
let _v = unwrap_or_else(optional_values, || default_values());
// the same, expliciting the return type:
let _v = unwrap_or_else(optional_values, || -> & [u32] {default_values()});
它可以编译:现在返回类型的生存期与optional_values
生存期兼容。
最后,我无法解释为什么,但是证据表明强制转换as fn() -> &'static _
帮助编译器确保绑定到optional_values
和default_values
的去耦生存期是安全的