2017-11-25 351 views
0

我試圖實現對所有Iterator<Item = Result<Type, E>>其中E是通用的擴展特性,生成另一個IteratorResult<OtherType, E>,其中從原來的錯誤被轉發。一直延伸迭代器<項目=結果<Type, E>>變換型

的問題是,該變換Type -> OtherType可能會失敗(該函數是f(t: Type) -> Result<OtherType, ConcreteError>

THEREFOR,迭代可能會從底層迭代器或混凝土錯誤類型,這當然是不可能返回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` 

回答

3

高度建議閱讀The Rust Programming Language。它充滿了新的Rust程序員應該知道的信息。

可能返回E [...]或混凝土錯誤類型

一個鏽的令人興奮的功能是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(_) => {} 
     } 
    } 
} 
+0

感謝提書。我已經做了一個Rust程序員兩年了,我已經多次閱讀過它。我只是覺得可能有辦法做到這一點,返回結果'(沒有枚舉助手)。 – musicmatze

+0

謝謝,這工作。如果你想看到真實的代碼:https://github.com/matthiasbeyer/imag/pull/1163 – musicmatze

相關問題