Closures 如何为闭包参数声明生存期?

Closures 如何为闭包参数声明生存期?,closures,rust,lifetime,Closures,Rust,Lifetime,我想为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

我想为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");
}
使用std::str::SplitWhitespace;
pub结构解析错误{
发布消息:String,
}
fn缺少\u令牌(行\u编号:usize)->解析器错误{
解析器错误{
消息:格式!(“{}行中缺少令牌,第_行编号),
}
}
fn进程\u字符串(行:&str,行编号:usize)->结果{
让mut tokens=line.split_whitespace();
匹配try!(tokens.next().ok_或(缺少_标记(行编号))){
“hi”=>println!(“hi”),
_=>println!(“其他东西”),
}
//下面的代码给出了“无法推断适当的生存期…”。。。。。
//设nt=| t:&mut SplitWhitespace | t.next().ok_或(缺少_标记(行编号));
//匹配尝试!(nt(&mut令牌)){
//“there”=>println!(“there”),
//_=>println!(“”),
// }
//我应该在哪里声明生命“a”?
//设nt=| t:&'a mut SplitWhitespace | t.next().ok_或(缺少_标记(行编号));
//匹配尝试!(nt(&mut令牌)){
//“there”=>println!(“there”),
//_=>println!(“”),
// }
返回Ok(());
}
fn main(){
处理字符串(“你好”,5).ok().expect(“Error!!!”);
处理字符串(“,5).ok().expect(“错误!!!2”);
}

error[E0495]:由于需求冲突,无法为生存期参数“%a”推断适当的生存期
-->src/main.rs:22:42
|
22 | let nt=|t:&mut SplitWhitespace | t.next().ok_或(缺少_标记(行号));
|                                          ^^^^
|
注意:首先,生命周期不能超过22:14在身体上定义的匿名生命周期#2。。。
-->src/main.rs:22:14
|
22 | let nt=|t:&mut SplitWhitespace | t.next().ok_或(缺少_标记(行号));
|              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
=注意:…以便类型兼容:
应为std::iter::迭代器
找到std::iter::迭代器
注意:但是,生命周期必须对23:16的呼叫有效。。。
-->src/main.rs:23:16
|
23 |匹配尝试!(nt和mut令牌)){
|                ^^^^^^^^^^^^^^^
注意:…因此表达式的'std::result::result'类型在表达式运行期间有效
-->src/main.rs:23:16
|
23 |匹配尝试!(nt和mut令牌)){
|                ^^^^^^^^^^^^^^^

我如何为这个闭包声明生存期
'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.
如果您以后实际上不需要使用
代币执行任何其他操作,只需执行以下操作:

let mut nt = || tokens.next().ok_or(missing_token(line_number)); 

另一种解决方案是编写一个函数来模拟闭包所做的事情,并调用它。

mut SplitWhitespace
实际上是一个
&'b mut SplitWhitespace(line:&'a str,line_number:usize)->结果{
然后将生存期添加到闭包中的类型:

let nt = |t: &mut SplitWhitespace<'a>| t.next().ok_or(missing_token(line_number));
let nt=|t:&mut SplitWhitespace与最初一样,您可以使用函数对闭包的参数和返回值应用额外的约束:

fn constrain<F>(f: F) -> F
where
    F: for<'a> Fn(&'a mut SplitWhitespace) -> Result<&'a str, ParserError>,
{
    f
}
最终,这是由于。特别是,如果闭包立即传递给使用它的函数,编译器可以推断参数和返回类型。不幸的是,当它在使用前存储在变量中时,编译器不会执行相同级别的推断


这种解决方法之所以有效,是因为它会立即将闭包传递给函数,确定类型和生存期引用。

也无法管理它。当然,编写
fn
works
fn nt Resultrelated:这回答了问题,而不是问题;),但是@PeterSmit可能有点受@ker的影响。我都想这不是一个好的、惯用的解决方案,并且理解为什么某些构造会起作用或不起作用。对我来说,目前看来,如果在使用显式生存期或不使用显式生存期(例如作用域)之间存在选择,那么在大多数情况下,最好使用没有显式生存期的版本
fn constrain<F>(f: F) -> F
where
    F: for<'a> Fn(&'a mut SplitWhitespace) -> Result<&'a str, ParserError>,
{
    f
}
let nt = constrain(|t| t.next().ok_or(missing_token(line_number)));