简体   繁体   English

从闭包填充集合时,键入不匹配“绑定生命周期参数”与“具体生命周期”

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

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 HashMap and am trying to call insert on it from within a closure used by take_while . 我创建了一个HashMap并尝试在take_while使用的闭包内调用insert However, I have so far not managed to get it to compile due to type mismatches related to concrete / bound lifetimes. 但是,由于与具体/绑定生命周期相关的类型不匹配,到目前为止我还没有设法编译它。

Here is a simplified version of my code which exhibits the same error: 这是我的代码的简化版本,它表现出同样的错误:

use std::collections::HashSet;

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

Here are the errors I get: 以下是我得到的错误:

error[E0631]: type mismatch in closure arguments
 --> src/main.rs:6:21
  |
5 |     let mut insert = |k| seq.insert(k);
  |                      ----------------- found signature of `fn(_) -> _`
6 |     (1..10).cycle().take_while(insert);
  |                     ^^^^^^^^^^ expected signature of `for<'r> fn(&'r {integer}) -> _`

error[E0271]: type mismatch resolving `for<'r> <[closure@src/main.rs:5:22: 5:39 seq:_] as std::ops::FnOnce<(&'r {integer},)>>::Output == bool`
 --> src/main.rs:6:21
  |
6 |     (1..10).cycle().take_while(insert);
  |                     ^^^^^^^^^^ expected bound lifetime parameter, found concrete lifetime

How do I need to change the code for it to work? 我如何更改代码才能工作?

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. Iterator<Item = T>::take_while()接受类型FnMut(&T) -> bool的闭包 - 也就是说,它通过引用将每个元素传递给闭包。 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. 这非常自然,因为take_while()必须能够生成成功测试的元素,因此它不能通过值传递它。

This means that insert argument type is inferred to be &_ , and so HashSet 's generic parameter is also inferred as &_ . 这意味着insert参数类型被推断为&_ ,因此HashSet的泛型参数也被推断为&_ 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. 但是,这意味着您试图将对cycle()迭代器产生的临时值的引用存储到寿命更长的结构中。 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. 不幸的是,Rust并没有完全显示出这种推理,因为由于某些原因它无法推断数字类型是i32 ,它也无法推断出闭包的正确生命周期参数。 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);
  |         ^^^^^^^^^^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM