0

I'm trying to implement an extension trait for all Iterator<Item = Result<Type, E>> where E is generic, to generate another Iterator over Result<OtherType, E>, where the errors from the original are forwarded.

The problem is, that the transformation Type -> OtherType may fail (the function is f(t: Type) -> Result<OtherType, ConcreteError>.

Therefor, the iteration might return E (generic) from the underlying iterator or a concrete error type, which is of course not possible.

How to implement this?

A minimal example:

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

Errors:

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`
4

1 回答 1

3

强烈推荐阅读Rust 编程语言。它充满了新的 Rust 程序员应该知道的信息。

可能返回E[...] 或具体的错误类型

Rust 令人兴奋的特性之一是enum枚举允许您创建可以是多种其他类型之一的类型。在这种情况下,我们可以将枚举定义为基础错误或我们自己的:

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(_) => {}
        }
    }
}
于 2017-11-25T16:28:00.120 回答