我如何在 Rust 中编写一个函数来接受其 Item 满足特征的任何迭代器?
How do I write a function in Rust that accepts any iterator whose Item fulfills a trait?
这是我想要实现的人为示例:
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());
}
这里的错误是"expected integral variable, found &Double
"。
我在谷歌搜索时遇到了麻烦,因为到处都在谈论迭代器作为特征。我正在尝试做的事情是否可行?
是的,这是可能的。您需要使用 where
子句来指定关联类型的界限 I::Item
.
fn foo<I>(is: I)
where I: Iterator,
I::Item: Double,
{
for i in is {
println!("{}", i.get());
}
}
(我还将 I: Iterator
绑定移动到 where
子句以将所有边界保持在一起。)
绑定 Iterator<Item = &'a Double>>
表示您需要一个迭代器,它产生的项目恰好是 &Double
类型的项目,它表示特征 Double
的特征对象。但是你想要一个迭代器来产生任何实现特征 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());
}
}
但您也可以只绑定关联的迭代器类型(参见):
fn foo<I>(is: I)
where I: Iterator,
I::Item: Double,
{ ... }
但是,这两个版本略有不同,因为一个版本接受对实现 Double
的类型的引用的迭代器,而另一个版本直接迭代实现 Double
的类型。只需使用最适合你的东西,或者将这两个东西概括为 AsRef
.
等特征
这是我想要实现的人为示例:
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());
}
这里的错误是"expected integral variable, found &Double
"。
我在谷歌搜索时遇到了麻烦,因为到处都在谈论迭代器作为特征。我正在尝试做的事情是否可行?
是的,这是可能的。您需要使用 where
子句来指定关联类型的界限 I::Item
.
fn foo<I>(is: I)
where I: Iterator,
I::Item: Double,
{
for i in is {
println!("{}", i.get());
}
}
(我还将 I: Iterator
绑定移动到 where
子句以将所有边界保持在一起。)
绑定 Iterator<Item = &'a Double>>
表示您需要一个迭代器,它产生的项目恰好是 &Double
类型的项目,它表示特征 Double
的特征对象。但是你想要一个迭代器来产生任何实现特征 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());
}
}
但您也可以只绑定关联的迭代器类型(参见
fn foo<I>(is: I)
where I: Iterator,
I::Item: Double,
{ ... }
但是,这两个版本略有不同,因为一个版本接受对实现 Double
的类型的引用的迭代器,而另一个版本直接迭代实现 Double
的类型。只需使用最适合你的东西,或者将这两个东西概括为 AsRef
.