扩展所有 Iterators<Item = Result<Type, E>> 以转换类型

Extending all Iterators<Item = Result<Type, E>> to transform type

我正在尝试为所有 Iterator<Item = Result<Type, E>> 实施扩展特征,其中 E 是通用的,以在 Result<OtherType, E> 上生成另一个 Iterator,其中错误来自原件已转发。

问题是,转换 Type -> OtherType 可能会失败(函数是 f(t: Type) -> Result<OtherType, ConcreteError>

因此,迭代可能 return E(通用)来自底层迭代器或具体错误类型,这当然是不可能的。

如何实现?

一个最小的例子:

pub struct A;
pub struct B;
pub struct CongreteError;

fn transform(a: A) -> Result<B, CongreteError> {
    Ok(B {})
}

pub struct ExtensionIter<E>(Box<Iterator<Item = Result<A, E>>>);

impl<E> Iterator for ExtensionIter<E> {
    type Item = Result<B, E>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.0.next() {
            Some(Ok(a)) => Some(transform(a)),
            Some(Err(e)) => Some(Err(e)),
            None => None,
        }
    }
}

pub trait Extension<E> {
    fn extend(self) -> ExtensionIter<E>;
}

impl<E, I> Extension<E> for I
where
    I: Iterator<Item = Result<A, E>>,
{
    fn extend(self) -> ExtensionIter<E> {
        ExtensionIter(Box::new(self))
    }
}

fn main() {
    let v: Vec<A> = vec![];
    for element in v.iter().extend() {
        match element {
            Ok(b) => {}
            Err(e) => {}
        }
    }
}

playground

错误:

error[E0308]: mismatched types
  --> src/main.rs:16:33
   |
16 |             Some(Ok(a)) => Some(transform(a)),
   |                                 ^^^^^^^^^^^^ expected type parameter, found struct `CongreteError`
   |
   = note: expected type `std::result::Result<_, E>`
              found type `std::result::Result<_, CongreteError>`
   = help: here are some functions which might fulfill your needs:
           - .map_err(...)
           - .or(...)
           - .or_else(...)

error[E0310]: the parameter type `I` may not live long enough
  --> src/main.rs:32:23
   |
27 | impl<E, I> Extension<E> for I
   |         - help: consider adding an explicit lifetime bound `I: 'static`...
...
32 |         ExtensionIter(Box::new(self))
   |                       ^^^^^^^^^^^^^^
   |
note: ...so that the type `I` will meet its required lifetime bounds
  --> src/main.rs:32:23
   |
32 |         ExtensionIter(Box::new(self))
   |                       ^^^^^^^^^^^^^^

error[E0599]: no method named `extend` found for type `std::slice::Iter<'_, A>` in the current scope
  --> src/main.rs:38:29
   |
38 |     for element in v.iter().extend() {
   |                             ^^^^^^
   |
   = note: the method `extend` exists but the following trait bounds were not satisfied:
           `std::slice::Iter<'_, A> : Extension<_>`
           `&std::slice::Iter<'_, A> : Extension<_>`
           `&mut std::slice::Iter<'_, A> : Extension<_>`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `extend`, perhaps you need to implement it:
           candidate #1: `Extension`

高度推荐阅读The Rust Programming Language。它充满了新 Rust 程序员应该知道的信息。

might return E [...] or a concrete error type

Rust 的一个令人兴奋的功能是 enums。枚举允许您创建可以是多种其他类型之一的类型。在这种情况下,我们可以将枚举定义为底层错误或我们自己的:

pub enum ExtensionError<E> {
    Original(E),
    Concrete(ConcreteError),
}

那么这只是从一种类型映射到另一种类型的问题:

pub struct A;
pub struct B;
pub struct ConcreteError;

fn transform(_: A) -> Result<B, ConcreteError> {
    Ok(B {})
}

pub struct ExtensionIter<I>(I);
pub enum ExtensionError<E> {
    Original(E),
    Concrete(ConcreteError),
}

impl<I, E> Iterator for ExtensionIter<I>
where
    I: Iterator<Item = Result<A, E>>,
{
    type Item = Result<B, ExtensionError<E>>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.0.next() {
            Some(Ok(a)) => Some(transform(a).map_err(ExtensionError::Concrete)),
            Some(Err(e)) => Some(Err(ExtensionError::Original(e))),
            None => None,
        }
    }
}

pub trait Extension: Iterator {
    fn extend(self) -> ExtensionIter<Self>
    where
        Self: Sized,
    {
        ExtensionIter(self)
    }
}

impl<I: Iterator> Extension for I {}

fn main() {
    let v: Vec<Result<A, ()>> = vec![];
    for element in v.into_iter().extend() {
        match element {
            Ok(_) => {}
            Err(_) => {}
        }
    }
}