Type mismatch “bound lifetime parameter” vs “concrete lifetime” when filling a collection from a closure

前端 未结 1 634
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-12 02:01

I am trying to find repetitions in an iterable sequence. Furthermore, I want to know the elements that occurred in that sequence up to that point.

I created a

1条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-01-12 02:31

    This is in fact a borrowing error in disguise.

    Iterator::take_while() accepts a closure of kind FnMut(&T) -> bool - that is, it passes each element to the closure by reference. This is pretty much natural because take_while() must be able to yield the successfully tested element, so it can't pass it by value.

    This means that insert argument type is inferred to be &_, and so HashSet's generic parameter is also inferred as &_. However, this means that you're attempting to store references to temporary values yielded by the cycle() iterator to a structure which lives much longer. This is not allowed by borrowing rules. Unfortunately, Rust doesn't show exactly this reasoning because for some reason it can't infer that the numeric type is i32 and it also can't infer the correct lifetime parameter for the closure. That's what your error is about.

    Instead, your closure should dereference the argument before storing it to the set. This works:

    use std::collections::HashSet;
    
    fn main() {
        let mut seq = HashSet::new();
        let mut insert = |&k: &i32| seq.insert(k);
        (1..10).cycle().take_while(insert);
    }
    

    I had to add the full type of the argument too; as I said above, I think that the type inference is not powerful enough to deduce it.

    BTW, you can actually get the borrow checker error if you specify the type explicitly:

    use std::collections::HashSet;
    
    fn main() {
        let mut seq = HashSet::new();
        let mut insert = |k: &i32| seq.insert(k);  // no dereference
        (1..10).cycle().take_while(insert);
    }
    

    The code above is equivalent to your original example except for the explicit type annotation, and it results in the following error:

    error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
     --> src/main.rs:5:43
      |
    5 |     let mut insert = |k: &i32| seq.insert(k);
      |                                           ^
      |
    note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the body at 5:22...
     --> src/main.rs:5:22
      |
    5 |     let mut insert = |k: &i32| seq.insert(k);
      |                      ^^^^^^^^^^^^^^^^^^^^^^^
    note: ...so that expression is assignable (expected &i32, found &i32)
     --> src/main.rs:5:43
      |
    5 |     let mut insert = |k: &i32| seq.insert(k);
      |                                           ^
    note: but, the lifetime must be valid for the block suffix following statement 1 at 5:5...
     --> src/main.rs:5:5
      |
    5 | /     let mut insert = |k: &i32| seq.insert(k);
    6 | |     (1..10).cycle().take_while(insert);
    7 | | }
      | |_^
    note: ...so that variable is valid at time of its declaration
     --> src/main.rs:5:9
      |
    5 |     let mut insert = |k: &i32| seq.insert(k);
      |         ^^^^^^^^^^
    

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