"cannot infer an appropriate lifetime" 当使用闭包时 return 对枚举变体内容的引用
"cannot infer an appropriate lifetime" when using a closure to return a reference to an enum variant's content
我有一个接受枚举引用的函数,我需要通过匹配枚举并读取其内容来解析它。枚举的一种变体(不在下面的简化最小工作示例中)可能包含枚举本身的类型作为值,因此我可能需要递归调用相同的函数来解析它的值。
我想编写一个充当过滤器的函数和 returns 一个 Option::Some
包含对枚举变体内容的引用,或者 None
如果值必须被丢弃。
接下来是一个最小的工作(非真正编译)示例:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
let equal = |d: &Data| -> Option<&String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
};
parse(&d, equal);
//parse(&d, equal_filter);
}
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
我尝试先使用闭包来编译代码,但在那种情况下出现错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:11:33
|
11 | if let Data::Value(s) = d {
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 10:17...
--> src/main.rs:10:17
|
10 | let equal = |d: &Data| -> Option<&String> {
| _________________^
11 | | if let Data::Value(s) = d {
12 | | Some(s)
13 | | } else {
14 | | None
15 | | }
16 | | };
| |_____^
= note: ...so that the types are compatible:
expected &Data<'_>
found &Data<'_>
note: but, the lifetime must be valid for the expression at 18:5...
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
note: ...so that a type/lifetime parameter is in scope here
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
所以我尝试了一个函数,但又遇到了另一个错误:
error[E0271]: type mismatch resolving `for<'r> <for<'a, 's> fn(&'a Data<'s>) -> std::option::Option<&'a std::string::String> {equal_filter} as std::ops::FnOnce<(&'r Data<'_>,)>>::Output == std::option::Option<&std::string::String>`
--> src/main.rs:19:5
|
19 | parse(&d, equal_filter);
| ^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `parse`
--> src/main.rs:30:1
|
30 | / fn parse<'a, F>(data: &Data<'a>, filter: F)
31 | | where
32 | | F: Fn(&Data<'a>) -> Option<&'a String>,
33 | | {
34 | | filter(data);
35 | | }
| |_^
我更愿意使用闭包来解决问题,但即使使用函数我也不知道如何进行。
归根结底,这是由于limitations in Rust's type inference造成的。具体来说,如果将闭包立即传递给使用它的函数,编译器可以推断出参数和 return 类型是什么。不幸的是,当它在使用前存储在变量中时,编译器不会执行相同级别的推理。
内联你的闭包并且有效:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, |d| match d {
Data::Value(s) => Some(s),
_ => None,
});
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
但是,我鼓励您改为在枚举上创建方法并参与 idiomatic set of conversion functions:
enum Data<'a> {
Value(&'a String),
Null,
}
impl<'a> Data<'a> {
fn as_value(&self) -> Option<&'a str> {
match self {
Data::Value(s) => Some(s),
_ => None,
}
}
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, Data::as_value);
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a str>,
{
filter(data);
}
您的函数变体不起作用,因为您将相关的生命周期放在了错误的位置:
// Wrong
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String>
// Right
fn equal_filter<'a>(d: &Data<'a>) -> Option<&'a String>
使用 #[deny(elided_lifetimes_in_paths)]
或 #[deny(rust_2018_idioms)]
将指导您这样做:
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:12:22
|
12 | let equal = |d: &Data| -> Option<&String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
|
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:24:28
|
24 | fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
另请参阅:
我有一个接受枚举引用的函数,我需要通过匹配枚举并读取其内容来解析它。枚举的一种变体(不在下面的简化最小工作示例中)可能包含枚举本身的类型作为值,因此我可能需要递归调用相同的函数来解析它的值。
我想编写一个充当过滤器的函数和 returns 一个 Option::Some
包含对枚举变体内容的引用,或者 None
如果值必须被丢弃。
接下来是一个最小的工作(非真正编译)示例:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
let equal = |d: &Data| -> Option<&String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
};
parse(&d, equal);
//parse(&d, equal_filter);
}
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
if let Data::Value(s) = d {
Some(s)
} else {
None
}
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
我尝试先使用闭包来编译代码,但在那种情况下出现错误:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:11:33
|
11 | if let Data::Value(s) = d {
| ^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 10:17...
--> src/main.rs:10:17
|
10 | let equal = |d: &Data| -> Option<&String> {
| _________________^
11 | | if let Data::Value(s) = d {
12 | | Some(s)
13 | | } else {
14 | | None
15 | | }
16 | | };
| |_____^
= note: ...so that the types are compatible:
expected &Data<'_>
found &Data<'_>
note: but, the lifetime must be valid for the expression at 18:5...
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
note: ...so that a type/lifetime parameter is in scope here
--> src/main.rs:18:5
|
18 | parse(&d, equal);
| ^^^^^
所以我尝试了一个函数,但又遇到了另一个错误:
error[E0271]: type mismatch resolving `for<'r> <for<'a, 's> fn(&'a Data<'s>) -> std::option::Option<&'a std::string::String> {equal_filter} as std::ops::FnOnce<(&'r Data<'_>,)>>::Output == std::option::Option<&std::string::String>`
--> src/main.rs:19:5
|
19 | parse(&d, equal_filter);
| ^^^^^ expected bound lifetime parameter, found concrete lifetime
|
note: required by `parse`
--> src/main.rs:30:1
|
30 | / fn parse<'a, F>(data: &Data<'a>, filter: F)
31 | | where
32 | | F: Fn(&Data<'a>) -> Option<&'a String>,
33 | | {
34 | | filter(data);
35 | | }
| |_^
我更愿意使用闭包来解决问题,但即使使用函数我也不知道如何进行。
归根结底,这是由于limitations in Rust's type inference造成的。具体来说,如果将闭包立即传递给使用它的函数,编译器可以推断出参数和 return 类型是什么。不幸的是,当它在使用前存储在变量中时,编译器不会执行相同级别的推理。
内联你的闭包并且有效:
enum Data<'a> {
Value(&'a String),
Null,
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, |d| match d {
Data::Value(s) => Some(s),
_ => None,
});
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a String>,
{
filter(data);
}
但是,我鼓励您改为在枚举上创建方法并参与 idiomatic set of conversion functions:
enum Data<'a> {
Value(&'a String),
Null,
}
impl<'a> Data<'a> {
fn as_value(&self) -> Option<&'a str> {
match self {
Data::Value(s) => Some(s),
_ => None,
}
}
}
fn main() {
let s = String::new();
let d = Data::Value(&s);
parse(&d, Data::as_value);
}
fn parse<'a, F>(data: &Data<'a>, filter: F)
where
F: Fn(&Data<'a>) -> Option<&'a str>,
{
filter(data);
}
您的函数变体不起作用,因为您将相关的生命周期放在了错误的位置:
// Wrong
fn equal_filter<'a>(d: &'a Data) -> Option<&'a String>
// Right
fn equal_filter<'a>(d: &Data<'a>) -> Option<&'a String>
使用 #[deny(elided_lifetimes_in_paths)]
或 #[deny(rust_2018_idioms)]
将指导您这样做:
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:12:22
|
12 | let equal = |d: &Data| -> Option<&String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
|
error: hidden lifetime parameters in types are deprecated
--> src/main.rs:24:28
|
24 | fn equal_filter<'a>(d: &'a Data) -> Option<&'a String> {
| ^^^^- help: indicate the anonymous lifetime: `<'_>`
另请参阅: