【问题标题】:Type mismatch "bound lifetime parameter" vs "concrete lifetime" when filling a collection from a closure从闭包填充集合时,类型不匹配“绑定生命周期参数”与“具体生命周期”
【发布时间】:2016-02-21 19:15:27
【问题描述】:

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

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

这是我的代码的简化版本,显示相同的错误:

use std::collections::HashSet;

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

这是我得到的错误:

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

我需要如何更改代码才能使其工作?

【问题讨论】:

  • 很好奇,如果将闭包直接移动到 take_while 调用:is.gd/OgVK2i
  • @ker,它之所以有效,是因为您正在做一件微妙不同的事情 - 您在模式中使用了隐式取消引用,而原始代码没有这样做。

标签: closures rust lifetime


【解决方案1】:

这其实是变相的借用错误。

Iterator&lt;Item = T&gt;::take_while() 接受FnMut(&amp;T) -&gt; bool 类型的闭包——也就是说,它通过引用将每个元素传递给闭包。这很自然,因为take_while() 必须能够产生成功测试的元素,所以它不能通过值传递它。

这意味着insert参数类型被推断为&amp;_,因此HashSet的泛型参数也被推断为&amp;_。但是,这意味着您正在尝试将由 cycle() 迭代器产生的临时值的引用存储到一个寿命更长的结构中。这是借用规则所不允许的。不幸的是,Rust 并没有准确地展示这种推理,因为由于某种原因它不能推断出数字类型是 i32 并且它也不能推断出闭包的正确生命周期参数。这就是你的错误所在。

相反,您的闭包应该在将参数存储到集合之前取消引用它。 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);
}

我也必须添加参数的完整类型;就像我上面说的,我认为类型推断不够强大,无法推断出来。

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

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);
}

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

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);
  |         ^^^^^^^^^^

【讨论】:

  • “我也必须添加参数的完整类型;正如我上面所说,我认为类型推断功能不足以推断它。”我遇到过几次这样的错误。它总是在 let 绑定中使用闭包。它们的实例化方式似乎有所不同。不将参数的类型指定为引用,则推断的引用似乎与闭包范围的生命周期早期绑定,而将类型指定为引用会导致闭包具有预期的更高种类的生命周期。跨度>
猜你喜欢
  • 2014-09-10
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
相关资源
最近更新 更多