当迭代Iterator
对时,我正在尝试为Rust的(K, V)
写一些简单的扩展方法。我可以为映射键想到的最简单的实现包括像这样重用Iterator::map
:
use std::iter::Map;
trait KeyedIterator<K, V>: Iterator<Item = (K, V)> {
fn map_keys<R, F, G>(self, f: F) -> Map<Self, G>
where
Self: Sized,
F: FnMut(K) -> R,
G: FnMut((K, V)) -> (R, V),
{
self.map(|(key, value): (K, V)| (f(key), value))
}
}
impl<I, K, V> KeyedIterator<K, V> for I where I: Iterator<Item = (K, V)> {}
但是,它出现此错误:
error[E0308]: mismatched types
--> src/lib.rs:10:18
|
10 | self.map(|(key, value): (K, V)| (f(key), value))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter, found closure
|
= note: expected type `G`
found type `[closure@src/lib.rs:10:18: 10:56 f:_]`
闭包是否应该实现G
,因为它是从(K, V)
到(R, V)
的函数?我在这里想念什么?
答案 0 :(得分:4)
如果为类型或函数声明类型参数,则该类型必须由调用方提供。但是,在您的代码中,您试图根据在其中定义的闭包的类型来确定G
主体中的类型map_keys
。
通常,让函数体确定类型的方法是使用存在返回类型(例如Map<Self, impl FnMut((K, V)) -> (R, V)>
。但是,这在trait方法中是不允许的。
用于所有内置迭代器适配器的模式将适用于您的用例。也就是说,定义一个结构,该结构由您的方法返回并使其成为迭代器:
// Struct to hold the state of the iterator
struct KeyedIter<I, F> {
iter: I,
f: F,
}
// Make KeyedIter an iterator whenever `I` is an iterator over tuples and `F` has the
// correct signature
impl<K, V, R, I, F> Iterator for KeyedIter<I, F>
where
I: Iterator<Item = (K, V)>,
F: FnMut(K) -> R,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|(k, _v)| (self.f)(k))
}
}
// A trait for adding the `map_keys` method
trait KeyedIterator<K, V> {
fn map_keys<R, F>(self, f: F) -> KeyedIter<Self, F>
where
F: FnMut(K) -> R,
Self: Sized;
}
// implement the trait for all iterators over tuples
impl<I, K, V> KeyedIterator<K, V> for I
where
I: Iterator<Item = (K, V)>,
{
fn map_keys<R, F>(self, f: F) -> KeyedIter<Self, F>
where
F: FnMut(K) -> R,
Self: Sized,
{
KeyedIter { iter: self, f }
}
}
KeyedIter
结构由调用者知道的类型进行参数化:上一个迭代器和映射函数。无需尝试表达中间闭包的类型-而是在迭代器的next()
方法中懒惰地对其进行处理。
另请参阅:
答案 1 :(得分:0)
G
受该方法的约束,并针对每个函数调用所传递的具体类型进行抽象。例如:
fn print<T: core::fmt::Debug>(t: T) {
println!("{:?}", t);
}
fn main() {
print(1);
print(1f64);
print("1");
}
这意味着不可能返回任意固定 G
的实现,但是有一些解决方法。
1-静态调度。必须修改代码以接收并返回相同的泛型:
use core::iter::Map;
trait KeyedIterator<K, V>: Iterator<Item = (K, V)> {
fn map_keys<R, F>(self, f: F) -> Map<Self, F>
where
Self: Sized,
F: FnMut((K, V)) -> (R, V),
{
self.map(f)
}
}
impl<I, K, V> KeyedIterator<K, V> for I where I: Iterator<Item = (K, V)> {}
fn main() {
let vec = vec![(1u32, 2i32), (3, 4), (5, 6)];
println!("{:?}", vec.into_iter().map_keys(|(k, v)| (k as f64 + 0.8, v)).collect::<Vec<(f64, i32)>>());
}
2-动态调度。只需少量的运行时开销,您就可以使用Box
。
trait KeyedIterator<K, V>: Iterator<Item = (K, V)> {
fn map_keys<'a, R, F: 'a>(self, mut f: F) -> Box<Iterator<Item = (R, V)> + 'a>
where
Self: Sized + 'a,
F: FnMut(K) -> R
{
Box::new(self.map(move |(key, value): (K, V)| (f(key), value)))
}
}
impl<I, K, V> KeyedIterator<K, V> for I where
I: Iterator<Item = (K, V)> {}
fn main() {
let vec = vec![(1u32, 2i32), (3, 4), (5, 6)];
println!(
"{:?}",
vec.into_iter()
.map_keys(|k| k as f64 + 0.8)
.collect::<Vec<(f64, i32)>>()
);
}