【问题标题】:How do I write a function in Rust that accepts any iterator whose Item fulfills a trait?如何在 Rust 中编写一个函数来接受其 Item 满足某个特征的任何迭代器?
【发布时间】:2017-03-27 23:12:28
【问题描述】:

这是我试图实现的一个人为的例子:

trait Double {
    fn get(&self) -> i32;
}

impl Double for i32 {
    fn get(&self) -> i32 { self * 2 }
}

fn foo<'a, I: Iterator<Item = &'a Double>>(is: I) {
    for i in is {
        println!("{}", i.get());
    }
}

fn main() {
    let is = vec![1, 2, 3, 4];
    foo(is.into_iter());
}

这里的错误是“预期的整数变量,找到&amp;Double”。

我在谷歌搜索时遇到了麻烦,因为到处都在谈论迭代器作为特征。我正在尝试做的事情是否可能?

【问题讨论】:

    标签: generics rust traits


    【解决方案1】:

    绑定的Iterator&lt;Item = &amp;'a Double&gt;&gt; 表示您需要一个迭代器,该迭代器产生的项目类型恰好为&amp;Double,它表示特征Double 的特征对象。但是你想要一个迭代器,它可以产生任何实现 trait Double 的类型。这听起来非常相似,因此令人困惑,但这都是关于动态与静态调度的。你应该阅读关于 trait objects 的 Rust 书籍章节,以了解到底发生了什么。

    但快速总结一下:写作之间是有区别的

    fn foo<T: MyTrait>(t: &T) {}
    

    fn foo(t: &MyTrait) {}
    

    您编写了与后者等效的代码,但实际上想要前者。


    那么你如何在代码中表达你的意图?一种可能是引入另一种类型参数!

    fn foo<'a, T, I>(is: I) 
        where T: Double,
              I: Iterator<Item = &'a T>,
    {
        for i in is {
            println!("{}", i.get());
        }
    }
    

    但你也可以只绑定迭代器的关联类型(见Francis Gagné's answer):

    fn foo<I>(is: I) 
        where I: Iterator,
              I::Item: Double,
    { ... }
    

    但是,这两个版本略有不同,因为一个版本接受一个迭代器来引用实现Double 的类型,而另一个版本则迭代直接实现Double 的类型。只需使用最适合您的东西,或者使用 AsRef 等特征概括这两件事。

    【讨论】:

    • 啊很好,所以这是静态调度是吗?我不想通过这样做引入开销。
    • @SamKellett 是的,确切地说,这是静态调度(动态调度仅在您看到&amp;MyTrait&amp;mut MyTraitBox&lt;MyTrait&gt; 之类的内容时使用)
    【解决方案2】:

    是的,这是可能的。您需要使用where 子句来指定关联类型I::Item 的绑定。

    fn foo<I>(is: I)
        where I: Iterator,
              I::Item: Double,
    {
        for i in is {
            println!("{}", i.get());
        }
    }
    

    (我还将I: Iterator 绑定到where 子句以保持所有边界在一起。)

    【讨论】:

    • 这很好,因为它没有添加额外的类型参数
    • 是的,这比我原来的解决方案要好。我也将此解决方案添加到我的答案中,因为您(Sam)已经接受了我的。我希望你不介意,弗朗西斯。
    • 没问题。但是,我们的解决方案并不完全相同:我的版本请求双精度迭代器,而您的版本请求双精度的 references 迭代器;您可能想提及这一点。
    • @FrancisGagné 哦,谢谢♥ 没注意。提到它:)
    猜你喜欢
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 2019-06-20
    • 2019-09-14
    相关资源
    最近更新 更多