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

Joe*_*Joe 9 closures lifetime rust

我试图在可迭代序列中找到重复.此外,我想知道在那个序列中发生的元素.

我创建了一个,HashMap并试图insert从使用的闭包中调用它take_while.但是,由于与具体/绑定生命周期相关的类型不匹配,到目前为止我还没有设法编译它.

这是我的代码的简化版本,它表现出同样的错误:

use std::collections::HashSet;

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

以下是我得到的错误:

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
Run Code Online (Sandbox Code Playgroud)

我如何更改代码才能工作?

Vla*_*eev 8

这实际上是伪装的借用错误.

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

这意味着insert参数类型被推断为&_,因此HashSet通用参数也被推断为&_.但是,这意味着您试图将对cycle()迭代器产生的临时值的引用存储到寿命更长的结构中.借用规则不允许这样做.不幸的是,Rust并没有完全显示出这种推理,因为由于某种原因,它无法推断数字类型i32,也无法推断出闭包的正确生命周期参数.这就是你的错误所在.

相反,您的闭包应该在将参数存储到集合之前取消引用该参数.这有效:

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);
}
Run Code Online (Sandbox Code Playgroud)

我也必须添加完整类型的参数; 正如我上面所说,我认为类型推断不足以推断出它.

顺便说一句,如果你明确指定了类型,你实际上可以得到借用检查器错误:

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);
}
Run Code Online (Sandbox Code Playgroud)

除了显式类型注释之外,上面的代码等同于您的原始示例,并且它会导致以下错误:

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);
  |         ^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)

  • "我也必须添加完整类型的参数;正如我上面所说,我认为类型推断不足以推断它." 我碰到了几次这样的错误.它始终与let绑定中的闭包.它们的实例化方式似乎有所不同.如果没有指定参数的类型作为引用,则结果推断引用似乎与闭包范围的生命周期早期绑定,而指定要作为引用的类型会导致具有预期更高的kinded生命周期的闭包. (2认同)