[英]“expected bound lifetime parameter” error when attempting to call a generic function
I am attempting to write a function that validates a given collection using a closure. 我试图编写一个使用闭包验证给定集合的函数。 The function takes ownership of a collection, iterates over the contents, and if no invalid item was found, returns ownership of the collection. 该函数获取集合的所有权,遍历内容,如果未找到无效的项目,则返回集合的所有权。 This is so it can be used like this (without creating a temp for the Vec
): let col = validate(vec![1, 2], |&v| v < 10)?;
这样就可以像这样使用它(无需为Vec
创建临时文件): let col = validate(vec![1, 2], |&v| v < 10)?;
This is the current implementation of the function: 这是该函数的当前实现:
use std::fmt::Debug;
fn validate<C, F, V>(col: C, pred: F) -> Result<C, String>
where C: Debug,
for<'c> &'c C: IntoIterator<Item = V>,
F: Fn(&V) -> bool,
V: Debug
{
if let Some(val) = (&col).into_iter().find(|v| !pred(v)) {
Err(format!("{:?} contains invalid item: {:?}.", col, val))?;
}
Ok(col)
}
It does compile, but it doesn't work when I try to use it: 它确实可以编译,但是当我尝试使用它时不起作用:
use std::collections::BTreeMap;
use std::iter::{FromIterator, once};
fn main() {
println!("Vec: {:?}", validate(vec![1, 2, 3, 4], |&&v| v <= 3));
// ^^^^^^^^ expected bound lifetime parameter 'c, found concrete lifetime
println!("Map: {:?}",
validate(BTreeMap::from_iter(once((1, 2))), |&(&k, &v)| k <= 3));
}
Is what I'm trying to accomplish here possible? 我要在这里完成的工作是否可能?
I am writing a parser for a toy project of mine and was wondering if I could write a single validate
function that works with all the collection types I use: Vec s, VecDeque s, BTreeSet s, BTreeMap s, &[T] slices . 我正在为我的一个玩具项目编写一个解析器,想知道我是否可以编写一个可以与我使用的所有集合类型一起使用的validate
函数: Vec , VecDeque , BTreeSet , BTreeMap , &[T] slices 。
Each of these collections implements the IntoIterator
trait for a reference of itself, which can be used to call .into_iter()
on a reference without consuming the items in the collection: 这些集合中的每一个都为自己的引用实现IntoIterator
特质,可用于在引用上调用.into_iter()
,而无需使用集合中的项目:
This is the what the for<'c> &'c C: IntoIterator<Item = V>
in the function declaration refers to. 这就是函数声明中的for<'c> &'c C: IntoIterator<Item = V>
所指的内容。 Since the reference is defined in the function body itself, we can't just use a lifetime that's declared on the function (like fn validate<'c, ...
), because this would imply that the reference has to outlive the function (which it cannot). 由于引用是在函数主体中定义的,因此我们不能仅使用在函数中声明的生存期(例如fn validate<'c, ...
),因为这意味着引用必须比函数寿命更长(它不能)。 Instead we have to use a Higher-Rank Trait Bound to declare this lifetime. 取而代之的是,我们必须使用更高等级的特质绑定来声明此生存期。
It seems to me that this lifetime is also the source of the trouble, since a version of the function that takes and returns a reference to the collection works fine: 在我看来,这个生存期也是麻烦的根源,因为接受并返回对集合的引用的函数版本可以正常工作:
// This works just fine.
fn validate<'c, C, F, V>(col: &'c C, pred: F) -> Result<&'c C, String>
where C: Debug,
&'c C: IntoIterator<Item = V>,
F: Fn(&V) -> bool,
V: Debug
{
if let Some(val) = col.into_iter().find(|v| !pred(v)) {
Err(format!("{:?} contains invalid item: {:?}.", col, val))?;
}
Ok(col)
}
Furthermore, I managed to implement two other versions of the function, one which works for Vec
, VecDeque
, BTreeSet
and &[T] slices
, and another which works for BTreeMap
and probably other mappings: 此外,我设法实现了该函数的其他两个版本,一个版本适用于Vec
, VecDeque
, BTreeSet
和&[T] slices
,另一个适用于BTreeMap
和可能的其他映射:
use std::fmt::Debug;
pub fn validate_collection<C, F, V>(col: C, pred: F) -> Result<C, String>
where C: Debug,
for<'c> &'c C: IntoIterator<Item = &'c V>,
F: Fn(&V) -> bool,
V: Debug
{
if let Some(val) = (&col).into_iter().find(|&v| !pred(v)) {
Err(format!("{:?} contains invalid item: {:?}.", col, val))?;
}
Ok(col)
}
pub fn validate_mapping<C, F, K, V>(col: C, pred: F) -> Result<C, String>
where C: Debug,
for<'c> &'c C: IntoIterator<Item = (&'c K, &'c V)>,
F: Fn(&K, &V) -> bool,
K: Debug,
V: Debug
{
if let Some(val) = (&col).into_iter().find(|&(k, v)| !pred(k, v)) {
Err(format!("{:?} contains invalid item: {:?}.", col, val))?;
}
Ok(col)
}
In the end I hope to create a Validate
trait. 最后,我希望创建一个Validate
特性。 Currently, I can only impl it for either collections or mappings, because the impls conflict. 目前,我只能将其隐含在集合或映射中,因为隐含冲突。
use std::fmt::Debug;
trait Validate<V>: Sized {
fn validate<F>(self, F) -> Result<Self, String> where F: Fn(&V) -> bool;
}
// Impl that only works for collections, not mappings.
impl<C, V> Validate<V> for C
where C: Debug,
for<'c> &'c C: IntoIterator<Item = &'c V>,
V: Debug
{
fn validate<F>(self, pred: F) -> Result<C, String>
where F: Fn(&V) -> bool
{
if let Some(val) = (&self).into_iter().find(|&v| !pred(v)) {
Err(format!("{:?} contains invalid item: {:?}.", self, val))?;
}
Ok(self)
}
}
fn main() {
println!("Vec: {:?}", vec![1, 2, 3, 4].validate(|&v| v <= 3));
}
Looking at your trait bounds (reformatted a little): 查看您的特征范围(重新格式化一点):
fn validate<C, F, V>(col: C, pred: F) -> Result<C, String>
where C: Debug,
for<'c> &'c C: IntoIterator<Item = V>,
F: Fn(&V) -> bool,
V: Debug {
the problem is that &C
won't implement IntoIterator<Item = V>
; 问题是&C
不会实现IntoIterator<Item = V>
; references tend to iterate over references. 引用倾向于遍历引用。
Fixing that (and the extra reference in the closure) makes it work: 修复该问题(以及闭包中的其他引用)可以使其起作用:
fn validate<C, F, V>(col: C, pred: F) -> Result<C, String>
where C: Debug,
for<'c> &'c C: IntoIterator<Item = &'c V>,
F: Fn(&V) -> bool,
V: Debug
{
if let Some(val) = (&col).into_iter().find(|v| !pred(v)) {
Err(format!("{:?} contains invalid item: {:?}.", col, val))?;
}
Ok(col)
}
fn main() {
println!("Vec: {:?}", validate(vec![1, 2, 3, 4], |&v| v <= 3));
}
To extend this to work with BTreeMap
values, we can abstract over the method used to generate the iterators. 为了将其扩展为与BTreeMap
值一起使用,我们可以抽象出用于生成迭代器的方法。 Let's add a trait HasValueIterator
which knows how to get an iterator over values: 让我们添加一个特征HasValueIterator
,它知道如何获取值的迭代器:
trait HasValueIterator<'a, V: 'a> {
type ValueIter : Iterator<Item=&'a V>;
fn to_value_iter(&'a self) -> Self::ValueIter;
}
and use that instead of IntoIterator
: 并使用它代替IntoIterator
:
fn validate<C, F, V>(col: C, pred: F) -> Result<C, String>
where C: Debug,
for<'c> C: HasValueIterator<'c, V>,
F: Fn(&V) -> bool,
V: Debug
{
if let Some(val) = (&col).to_value_iter().find(|v| !pred(v)) {
Err(format!("{:?} contains invalid item: {:?}.", col, val))?;
}
Ok(col)
}
Now we can implement it for Vec
and BTreeMap
(the latter using .values()
), thought you have to name the iterator types: 现在我们可以为Vec
和BTreeMap
(后者使用.values()
)实现它,以为您必须命名迭代器类型:
impl<'c, V:'c> HasValueIterator<'c, V> for Vec<V> {
type ValueIter = std::slice::Iter<'c,V>;
fn to_value_iter(&'c self) -> Self::ValueIter {
self.iter()
}
}
impl<'c, V:'c, K:'c> HasValueIterator<'c, V> for BTreeMap<K, V> {
type ValueIter = std::collections::btree_map::Values<'c, K, V>;
fn to_value_iter(&'c self) -> Self::ValueIter {
self.values()
}
}
Now this works with both Vec
and BTreeMap
, at least with values: 现在,这对Vec
和BTreeMap
都BTreeMap
,至少与值BTreeMap
:
fn main() {
println!("Vec: {:?}", validate(vec![1, 2, 3, 4], |&v| v <= 3));
let mut map = BTreeMap::new();
map.insert("first", 1);
map.insert("second", 2);
map.insert("third", 3);
println!("Map: {:?}", validate(map, |&v| v<=2));
}
This outputs: 输出:
Vec: Err("[1, 2, 3, 4] contains invalid item: 4.")
Map: Err("{\"first\": 1, \"second\": 2, \"third\": 3} contains invalid item: 3.")
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.