2016-08-08 4 views
0

Ich versuche, ein Paar Iteratoren zu gehen. Dies scheint konzeptionell ziemlich trivial zu sein, aber es ist tatsächlich nicht ausgedrückt worden.Wie ändere ich einen Wert nach dem Abgleich?

fn next(&mut self) -> Option<Self::Item> { 
    let mut left = self.left.next(); 
    let mut right = self.right.next(); 

    loop { 
     match (left, right) { 
      (Some(left_value), Some(right_value)) => { 
       match left_value.cmp(&right_value) { 
        Ordering::Equal => return Some((left_value, right_value)), 
        Ordering::Less => left = self.left.next(), 
        Ordering::Greater => right = self.right.next(), 
       } 
      } 

      _ => return None 
     } 
    } 
} 

Dies funktioniert nicht, weil links und rechts verschoben werden, wenn ich auf ihnen übereinstimmen. Wie kann man das erfolgreich ausdrücken?

Beispiel (auch als ganze Kiste bekannt):

use std::cmp::{Eq, Ord, Ordering}; 

pub trait AscendingIterator: Iterator where <Self as Iterator>::Item: Eq + Ord {} 

pub trait DescendingIterator: Iterator where <Self as Iterator>::Item: Eq + Ord {} 

pub struct AscendingIntersection<T, T1, T2> 
    where T: Eq + Ord, 
      T1: AscendingIterator<Item = T>, 
      T2: AscendingIterator<Item = T> 
{ 
    left: T1, 
    right: T2, 
} 

impl<T, T1, T2> Iterator for AscendingIntersection<T, T1, T2> 
    where T: Eq + Ord, 
      T1: AscendingIterator<Item = T>, 
      T2: AscendingIterator<Item = T> 
{ 
    type Item = (T, T); 

    fn next(&mut self) -> Option<Self::Item> { 
     let mut left = self.left.next(); 
     let mut right = self.right.next(); 

     loop { 
      match (left, right) { 
       (Some(left_value), Some(right_value)) => { 
        match left_value.cmp(&right_value) { 
         Ordering::Equal => return Some((left_value, right_value)), 
         Ordering::Less => left = self.left.next(), 
         Ordering::Greater => right = self.right.next(), 
        } 
       } 

       _ => return None, 
      } 
     } 
    } 
} 

Edit: Ich für dieses faul Beispiel entschuldigen; Die Menge an Tippen, die ich machen kann, ist durch eine nicht verwandte Radsportverletzung begrenzt.

+0

Würden Sie freundlicherweise eine [MCVE] produzieren? Zum Beispiel haben Sie zwei "match" -Anweisungen, daher ist unklar, was das Problem verursacht. Zusätzlich gibt es einen 'self' Parameter, aber wir können nicht sagen, was die Struktur selbst ist. Vielleicht könnte der Kern des Problems aus dem Kontext eines Iterators entfernt werden und als eine "match" -Anweisung direkt in "main" oder einer anderen kleinen Funktion ausgedrückt werden? – Shepmaster

Antwort

2

Ihre match (left, right) bewegt Werte aus left und right, so dass sie in der nächsten Iteration leer. Warum also nicht einfach zurückziehen?

Ordering::Less => { 
    left = self.left.next(); 
    right = Some(right_value); 
}, 
Ordering::Greater => { 
    left = Some(left_value); 
    right = self.right.next(); 
}, 

Nun, das ist immer noch ein bisschen hässlich. Eine schönere Möglichkeit, dies zu tun, ist die match insgesamt zu entfernen. Zuerst stehlen ein try_opt! - ich verwendet http://crumblingstatue.github.io/doc/try_opt/src/try_opt/lib.rs.html#1-37

macro_rules! try_opt { 
    ($e:expr) =>(
     match $e { 
      Some(v) => v, 
      None => return None, 
     } 
    ) 
} 

Dann tun nur

let mut left = try_opt!(self.left.next()); 
let mut right = try_opt!(self.right.next()); 

loop { 
    match left.cmp(&right) { 
     Ordering::Equal => return Some((left, right)), 
     Ordering::Less => left = try_opt!(self.left.next()), 
     Ordering::Greater => right = try_opt!(self.right.next()), 
    } 
} 
Verwandte Themen