如何解决如何为返回“impl Trait”的函数实现扩展特征模式?
假设我有以下辅助方法,它使用向量加法将两个迭代器(或 IntoIterator
s)相加:
fn add<I1,I2,T>(a: I1,b: I2) -> impl Iterator<Item = T>
where
I1: IntoIterator<Item = T>,I2: IntoIterator<Item = T>,T: std::ops::Add<Output = T>,{
a.into_iter().zip(b).map(|(x,y)| x + y)
}
可以如下使用:
fn main() {
let a = vec![1,2,3,4,5]; // Can use vectors
let b = (6..=10).map(|x| x + 1); // Or other complicated iterators
let sum_iter = add(a,b); // Can be used as an iterator if you wish to chain other functions
let sum_vec = sum_iter.collect::<Vec<i32>>(); // Or you can collect it
assert_eq!(sum_vec,vec![8,10,12,14,16]);
}
在实现这一点后,我决定我应该更改 API,以便我可以使用语法 a.add(b)
,这将使链接这些函数非常好。我尝试实现 extension trait 模式,但很快意识到这是不可能的,因为特征函数的返回类型不支持 impl Trait
,而且我的 add
函数无法指定具体的由于传递给 |(x,y)| x + y
.map()
而导致的类型
为了帮助澄清我的想法,这基本上是我尝试过的(显然这不能编译):
trait IntoIteratorMathExt
where
Self: IntoIterator,{
fn add<I>(self,other: I) -> impl Iterator<Item = Self::Item>
where
I: IntoIterator<Item = Self::Item>,Self::Item: std::ops::Add<Output = Self::Item>;
}
impl<T: IntoIterator> IteratorMathExt for T {
fn add<I>(self,other: I) -> impl Iterator<Item = Self::Item>
where
I: IntoIterator<Item = Self::Item>,Self::Item: std::ops::Add<Output = Self::Item>,{
self.into_iter().zip(other).map(|(x,y)| x + y)
}
}
fn main() {
let a = vec![1,5];
let b = (6..=10).map(|x| x + 1);
let sum_iter = a.add(b); // <- Really nice Syntax!
let sum_vec = sum_iter.collect::<Vec<i32>>();
assert_eq!(sum_vec,16]);
}
不出所料,这会导致以下编译器错误:
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src\main.rs:34:34
|
34 | fn add<I>(self,other: I) -> impl Iterator<Item = Self::Item>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and inherent method return types
--> src\main.rs:41:34
|
41 | fn add<I>(self,other: I) -> impl Iterator<Item = Self::Item>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我理解为什么特征方法不支持 impl Trait
,但是,我的特征“实际上”只在一个地方实现,所以我希望可能存在一种解决方法。
所以放弃这种方法,我想知道实现这种模式的“正确”方法是什么。
目标是能够使用迭代器 a
和 b
(Iterator
或 IntoIterator
,我不是 100% 是最好的),然后能够编写 a.add(b)
并让它返回一个 Iterator
,具有与 Item
和 a
相同的关联 b
类型。
有什么建议吗?
解决方法
由于你的闭包不捕获任何值,它实际上可以表示为一个函数指针类型,它允许你表达类型(它很丑,但它有效):
type MathExtType<A,B,T> = std::iter::Map<std::iter::Zip<A,B>,fn((T,T)) -> T>;
trait IntoIteratorMathExt
where
Self: IntoIterator,{
fn add<I>(self,other: I) -> MathExtType<Self::IntoIter,I::IntoIter,Self::Item>
where
I: IntoIterator<Item = Self::Item>,Self::Item: std::ops::Add<Output = Self::Item>;
}
impl<T: IntoIterator> IntoIteratorMathExt for T {
fn add<I>(self,Self::Item: std::ops::Add<Output = Self::Item>,{
self.into_iter().zip(other).map(|(x,y)| x + y)
}
}
fn main() {
let a = vec![1,2,3,4,5];
let b = (6..=10).map(|x| x + 1);
let sum_iter = a.add(b); // <- Really nice syntax!
let sum_vec = sum_iter.collect::<Vec<i32>>();
assert_eq!(sum_vec,vec![8,10,12,14,16]);
}
,
如果您愿意采用动态方式,事情会变得更容易。您只需返回一个 Box<dyn Iterator<Item=Self::Item>>
,一切都会好起来的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。