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

守給你的承諾、 提交于 2019-12-01 03:30:53
Vladimir Matveev

This is in fact a borrowing error in disguise.

Iterator<Item = T>::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);
  |         ^^^^^^^^^^
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!