当前位置: 首页 > 知识库问答 >
问题:

尝试调用泛型函数时出现“预期绑定生存期参数”错误

吕飞翼
2023-03-14

我试图编写一个函数,使用闭包验证给定的集合。该函数获取集合的所有权,对内容进行迭代,如果没有找到无效的项,则返回集合的所有权。这就是为什么它可以这样使用(而不需要为Vec创建一个temp):let ol=valester(vec![1,2],|

这是当前实现的功能

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函数,该函数适用于我使用的所有集合类型: Vecs,VecDeques,BTreeSets,BTreeMaps,

这些集合中的每一个都实现了自身引用的IntoIterator特性,可用于调用。在引用上插入到\u iter(),而不使用集合中的项目:

  • Vec impl

这就是的作用

在我看来,这个生命周期也是问题的根源,因为接受并返回集合引用的函数版本可以正常工作:

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

铁锈操场

此外,我还实现了该函数的另外两个版本,一个适用于VecVecDequeBTreeSet

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

铁锈操场

最后,我希望创建一个Validatetrait。目前,我只能为集合或映射impl它,因为impls冲突。

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

铁锈操场


共有1个答案

闻人和泽
2023-03-14

查看您的特征边界(稍微重新格式化):

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 {

问题是

修复该问题(以及闭包中的额外引用)使其工作:

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

游戏场

为了将其扩展到使用BTreeMap值,我们可以对用于生成迭代器的方法进行抽象。让我们添加一个traitHasValueIterator,它知道如何获取值的迭代器:

trait HasValueIterator<'a, V: 'a> {
    type ValueIter : Iterator<Item=&'a V>;

    fn to_value_iter(&'a self) -> Self::ValueIter;
}

并用它代替迭代器中的

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

现在我们可以为VecBTreeMap(后者使用.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()
    }

}

现在,这适用于VecBTreeMap,至少适用于以下值:

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

游戏场

这将产生:

Vec: Err("[1, 2, 3, 4] contains invalid item: 4.")
Map: Err("{\"first\": 1, \"second\": 2, \"third\": 3} contains invalid item: 3.")

 类似资料:
  • 我已将问题简化为以下代码: 函数还可以,但是当我替换具体类型

  • 关于这个主题已经有很多线程,但是我看不出讨论的问题是否适用于我的特定问题。 我有一个存储和函数的结构。简而言之,问题是这样的: 我想做的是存储一个与名称相关联的回调函数(将来可能会有更多内容)。 但当我尝试这样使用这段代码时: 我得到以下错误消息: 我试着像这样内联闭包 但是我又犯了一个错误 我相信我明白为什么我会这样。 在切换到一个函数引用以存储在我的命令结构中之前,我尝试使用一个通用类型参数,

  • 我目前正在听这个。我试图把它缩小到一个最小的可重复的例子。 这给我留下了: 以前,我将我的存储在像这样的中 但是现在我想重构一些东西,并引入了一个结构,并将东西存储为

  • 我使用实体管理器来创建一个本地查询。我的数据库是Postgres数据库。我请求的日期字段是这样建模的... 当我写这个的时候,一切都很好... 但是当我想使用setParameter函数时... 我有这个问题。。 知道吗?

  • 问题内容: 这是我的代码: 当我执行此操作时,将引发错误: 我确保它不是拼写错误,并且我没有拼错该函数的名称,所以为什么会出现NameError? 问题答案: 除非已定义函数,否则无法调用它。将块移动到文件的顶部,在导入的下面。 某些语言允许您在定义函数之前使用函数。例如,javascript将其称为“吊装”。但是Python并不是这些语言之一。 请注意,只要按 时间顺序 在使用前定义,就可以在比

  • 泛型用于通常我们放置类型的位置,比如函数签名或结构体,允许我们创建可以代替许多具体数据类型的结构体定义。让我们看看如何使用泛型定义函数、结构体、枚举和方法,并且在本部分的结尾我们会讨论泛型代码的性能。 定义函数时可以在函数签名的参数数据类型和返回值中使用泛型。以这种方式编写的代码将更灵活并能向函数调用者提供更多功能,同时不引入重复代码。 回到 函数上,示例 10-4 中展示了两个提供了相同的寻找