我将尝试编写一个使用闭包验证给定集合的函数。该函数接收一个集合,遍历其中的内容,并在未发现无效项时返回该集合的所有权。这样可以像这样使用它(而不需要为
在我看来,这个生命周期也是问题的根源,因为一个接受并返回集合引用的函数版本可以正常工作:
Vec
创建临时变量):let col = validate(vec![1, 2], |&v| v < 10)?;
以下是该函数的当前实现: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)
}
它确实编译通过,但在我尝试使用时却无法正常工作:
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));
}
我正在为我的玩具项目编写解析器,并想知道是否可以编写一个单一的validate
函数,以适用于我使用的所有集合类型:
Vec、
VecDeque、
BTreeSet、
BTreeMap和
&[T] slices。
这些集合中的每一个都为自己的引用实现了IntoIterator
trait,可以在不消耗集合中的项的情况下,
使用.into_iter()
在引用上调用:
for<'c> &'c C: IntoIterator<Item = V>
所指的内容。由于引用是在函数体内定义的,我们不能仅使用在函数上声明的生命周期(如fn validate<'c, ...
),因为这将意味着引用必须超出函数的生存期(而这是不可能的)。相反,我们必须使用Higher-Rank Trait Bound来声明此生命周期。在我看来,这个生命周期也是问题的根源,因为一个接受并返回集合引用的函数版本可以正常工作:
// 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)
}
此外,我还实现了另外两个版本的函数,一个适用于Vec
、VecDeque
、BTreeSet
和&[T]切片
,另一个适用于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)
}
最终,我希望创建一个Validate
特质。目前,我只能为集合或映射之一进行实现,因为实现会冲突。
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));
}
validate_collection
和validate_mapping
的代码块。 - Nikon the ThirdBTreeMap
值(但不是键/值)的方法。 - Chris Emerson