How to declare a lifetime for a closure argument?

后端 未结 3 678
無奈伤痛
無奈伤痛 2020-11-30 11:10

I would like to declare a lifetime for a closure in Rust, but I can\'t find a way to add a lifetime declaration.

use std::str::SplitWhitespace;

pub struct P         


        
相关标签:
3条回答
  • 2020-11-30 11:35

    As originally pointed out by DK., you can use a function to apply extra constraints to a closure's arguments and return values:

    fn constrain<F>(f: F) -> F
    where
        F: for<'a> Fn(&'a mut SplitWhitespace) -> Result<&'a str, ParserError>,
    {
        f
    }
    

    This gives you the full abilities of the where clause; in this case you can use higher-ranked trait bounds (for <...>) to say that the closure must return a reference of the same lifetime as the argument.

    let nt = constrain(|t| t.next().ok_or(missing_token(line_number)));
    

    Ultimately, this is caused due to limitations in Rust's type inference. Specifically, if a closure is passed immediately to a function that uses it, the compiler can infer what the argument and return types are. Unfortunately, when it is stored in a variable before being used, the compiler does not perform the same level of inference.

    This workaround works because it immediately passes the closure to a function, nailing down the types and lifetime references.

    0 讨论(0)
  • 2020-11-30 11:37

    The &mut SplitWhitespace is actually a &'b mut SplitWhitespace<'a>. The relevant lifetime here is the 'a, as it specifies how long the string slices that next returns live. Since you applied the split_whitespace function on your line argument, you need to set 'a to the same lifetime that the line argument has.

    So as a first step you add a lifetime to line:

    fn process_string<'a>(line: &'a str, line_number: usize) -> Result<(), ParserError> {
    

    and then you add the lifetime to the type in your closure:

    let nt = |t: &mut SplitWhitespace<'a>| t.next().ok_or(missing_token(line_number));
    

    Note that while this answers your question, the correct solution to your Problem is @A.B.'s solution.

    0 讨论(0)
  • 2020-11-30 11:50

    I don't know how to answer your question, but there are two ways to solve the problem:

    The easiest one is to let the closure reference the iterator directly.

    {
        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.
    

    If you don't actually need do anything else with tokens afterwards, just do:

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

    The other solution is to write a function that emulates what the closure is doing and call that instead.

    0 讨论(0)
提交回复
热议问题