如何为闭包参数声明更高级别的生命周期?
How to declare a higher-ranked lifetime for a closure argument?
我想在 Rust 中为闭包声明生命周期,但我找不到添加生命周期声明的方法。
use std::str::SplitWhitespace;
pub struct ParserError {
pub message: String,
}
fn missing_token(line_no: usize) -> ParserError {
ParserError {
message: format!("Missing token on line {}", line_no),
}
}
fn process_string(line: &str, line_number: usize) -> Result<(), ParserError> {
let mut tokens = line.split_whitespace();
match try!(tokens.next().ok_or(missing_token(line_number))) {
"hi" => println!("hi"),
_ => println!("Something else"),
}
// The following code gives "cannot infer appropriate lifetime.....
// let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
// match try!(nt(&mut tokens)) {
// "there" => println!("there"),
// _ => println!("_"),
// }
// Where should I declare the lifetime 'a?
// let nt = |t: &'a mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
// match try!(nt(&mut tokens)) {
// "there" => println!("there"),
// _ => println!("_"),
// }
return Ok(());
}
fn main() {
process_string("Hi there", 5).ok().expect("Error!!!");
process_string("", 5).ok().expect("Error!!! 2");
}
Complete sample code on the playground.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:22:42
|
22 | let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 22:14...
--> src/main.rs:22:14
|
22 | let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected std::iter::Iterator
found std::iter::Iterator
note: but, the lifetime must be valid for the call at 23:16...
--> src/main.rs:23:16
|
23 | match try!(nt(&mut tokens)) {
| ^^^^^^^^^^^^^^^
note: ...so type `std::result::Result<&str, ParserError>` of expression is valid during the expression
--> src/main.rs:23:16
|
23 | match try!(nt(&mut tokens)) {
| ^^^^^^^^^^^^^^^
如何声明此闭包的生命周期 'a
?
我不知道怎么回答你的问题,但是有两种方法可以解决这个问题:
最简单的方法是让闭包直接引用迭代器。
{
let mut nt = || tokens.next().ok_or(missing_token(line_number));
// call the closure as many times as you need to
}
// At this point `tokens` will be usable again.
如果您之后实际上不需要对 tokens
执行任何其他操作,只需执行:
let mut nt = || tokens.next().ok_or(missing_token(line_number));
另一个解决方案是编写一个函数来模拟闭包的作用并调用它。
这个&mut SplitWhitespace
实际上是一个&'b mut SplitWhitespace<'a>
。这里的相关生命周期是 'a
,因为它指定了 next
returns 的字符串切片的生命周期。由于您在 line
参数上应用了 split_whitespace
函数,因此您需要将 'a
设置为与 line
参数相同的生命周期。
因此,作为第一步,您将生命周期添加到 line
:
fn process_string<'a>(line: &'a str, line_number: usize) -> Result<(), ParserError> {
然后将生命周期添加到闭包中的类型:
let nt = |t: &mut SplitWhitespace<'a>| t.next().ok_or(missing_token(line_number));
请注意,虽然这回答了您的问题,但您问题的正确解决方案是 。
与最初 一样,您可以使用函数对闭包的参数和 return 值应用额外的约束:
fn constrain<F>(f: F) -> F
where
F: for<'a> Fn(&'a mut SplitWhitespace) -> Result<&'a str, ParserError>,
{
f
}
这为您提供了 where
子句的全部功能;在这种情况下,您可以使用 higher-ranked trait bounds (for <...>
) 来表示闭包必须 return 与参数具有相同生命周期的引用。
let nt = constrain(|t| t.next().ok_or(missing_token(line_number)));
归根结底,这是由于limitations in Rust's type inference造成的。具体来说,如果将闭包立即传递给使用它的函数,编译器可以推断出参数和 return 类型是什么。不幸的是,当它在使用前存储在变量中时,编译器不会执行相同级别的推理。
此变通方法有效,因为它立即将闭包传递给函数,确定类型和生命周期引用。
我想在 Rust 中为闭包声明生命周期,但我找不到添加生命周期声明的方法。
use std::str::SplitWhitespace;
pub struct ParserError {
pub message: String,
}
fn missing_token(line_no: usize) -> ParserError {
ParserError {
message: format!("Missing token on line {}", line_no),
}
}
fn process_string(line: &str, line_number: usize) -> Result<(), ParserError> {
let mut tokens = line.split_whitespace();
match try!(tokens.next().ok_or(missing_token(line_number))) {
"hi" => println!("hi"),
_ => println!("Something else"),
}
// The following code gives "cannot infer appropriate lifetime.....
// let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
// match try!(nt(&mut tokens)) {
// "there" => println!("there"),
// _ => println!("_"),
// }
// Where should I declare the lifetime 'a?
// let nt = |t: &'a mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
// match try!(nt(&mut tokens)) {
// "there" => println!("there"),
// _ => println!("_"),
// }
return Ok(());
}
fn main() {
process_string("Hi there", 5).ok().expect("Error!!!");
process_string("", 5).ok().expect("Error!!! 2");
}
Complete sample code on the playground.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
--> src/main.rs:22:42
|
22 | let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
| ^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 22:14...
--> src/main.rs:22:14
|
22 | let nt = |t: &mut SplitWhitespace| t.next().ok_or(missing_token(line_number));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the types are compatible:
expected std::iter::Iterator
found std::iter::Iterator
note: but, the lifetime must be valid for the call at 23:16...
--> src/main.rs:23:16
|
23 | match try!(nt(&mut tokens)) {
| ^^^^^^^^^^^^^^^
note: ...so type `std::result::Result<&str, ParserError>` of expression is valid during the expression
--> src/main.rs:23:16
|
23 | match try!(nt(&mut tokens)) {
| ^^^^^^^^^^^^^^^
如何声明此闭包的生命周期 'a
?
我不知道怎么回答你的问题,但是有两种方法可以解决这个问题:
最简单的方法是让闭包直接引用迭代器。
{
let mut nt = || tokens.next().ok_or(missing_token(line_number));
// call the closure as many times as you need to
}
// At this point `tokens` will be usable again.
如果您之后实际上不需要对 tokens
执行任何其他操作,只需执行:
let mut nt = || tokens.next().ok_or(missing_token(line_number));
另一个解决方案是编写一个函数来模拟闭包的作用并调用它。
这个&mut SplitWhitespace
实际上是一个&'b mut SplitWhitespace<'a>
。这里的相关生命周期是 'a
,因为它指定了 next
returns 的字符串切片的生命周期。由于您在 line
参数上应用了 split_whitespace
函数,因此您需要将 'a
设置为与 line
参数相同的生命周期。
因此,作为第一步,您将生命周期添加到 line
:
fn process_string<'a>(line: &'a str, line_number: usize) -> Result<(), ParserError> {
然后将生命周期添加到闭包中的类型:
let nt = |t: &mut SplitWhitespace<'a>| t.next().ok_or(missing_token(line_number));
请注意,虽然这回答了您的问题,但您问题的正确解决方案是
与最初
fn constrain<F>(f: F) -> F
where
F: for<'a> Fn(&'a mut SplitWhitespace) -> Result<&'a str, ParserError>,
{
f
}
这为您提供了 where
子句的全部功能;在这种情况下,您可以使用 higher-ranked trait bounds (for <...>
) 来表示闭包必须 return 与参数具有相同生命周期的引用。
let nt = constrain(|t| t.next().ok_or(missing_token(line_number)));
归根结底,这是由于limitations in Rust's type inference造成的。具体来说,如果将闭包立即传递给使用它的函数,编译器可以推断出参数和 return 类型是什么。不幸的是,当它在使用前存储在变量中时,编译器不会执行相同级别的推理。
此变通方法有效,因为它立即将闭包传递给函数,确定类型和生命周期引用。