从闭包中填充集合时类型不匹配 "bound lifetime parameter" 与 "concrete lifetime"
Type mismatch "bound lifetime parameter" vs "concrete lifetime" when filling a collection from a closure
我正在尝试在可迭代序列中查找重复项。此外,我想知道到那时为止该序列中出现的元素。
我创建了一个 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
我需要如何更改代码才能使其正常工作?
这其实是变相的借用错误
Iterator<Item = T>::take_while()
接受类型为 FnMut(&T) -> bool
的闭包——也就是说,它通过引用将每个元素传递给闭包。这很自然,因为 take_while()
必须能够生成测试成功的元素,所以它不能按值传递它。
这意味着 insert
参数类型被推断为 &_
,因此 HashSet
的泛型参数也被推断为 &_
。但是,这意味着您正试图将对 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);
| ^^^^^^^^^^
我正在尝试在可迭代序列中查找重复项。此外,我想知道到那时为止该序列中出现的元素。
我创建了一个 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
我需要如何更改代码才能使其正常工作?
这其实是变相的借用错误
Iterator<Item = T>::take_while()
接受类型为 FnMut(&T) -> bool
的闭包——也就是说,它通过引用将每个元素传递给闭包。这很自然,因为 take_while()
必须能够生成测试成功的元素,所以它不能按值传递它。
这意味着 insert
参数类型被推断为 &_
,因此 HashSet
的泛型参数也被推断为 &_
。但是,这意味着您正试图将对 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);
| ^^^^^^^^^^