2015-07-08 32 views
7

Sto provando a creare un tratto con funzioni che restituiscono un iteratore.tratto con funzioni che restituiscono un iteratore

mio semplice esempio si presenta così:

pub trait TraitA { 
    fn things(&self) -> Iterator<Item=&u8>; 
} 

fn foo<A: TraitA>(a: &A) { 
    for x in a.things() { } 
} 

che non funziona perché il tipo di formato Iterator non è noto al momento della compilazione.

+0

Se si utilizza un tipo associato, come suggerito nelle risposte qui sotto non è adatto (non può essere), allora si può tornare un 'Box >' invece. Ma questo richiederà un'allocazione dell'heap! – BurntSushi5

risposta

7

libstd di Rust ha un'esecuzione del presente, il tratto IntoIterator .

/// Conversion into an `Iterator` 
pub trait IntoIterator { 
    /// The type of the elements being iterated 
    type Item; 

    /// A container for iterating over elements of type `Item` 
    type IntoIter: Iterator<Item=Self::Item>; 

    /// Consumes `Self` and returns an iterator over it 
    fn into_iter(self) -> Self::IntoIter; 
} 

La caratteristica peculiare ha questa formulazione per valore (self) esattamente poter esprimere sia “in iteratore” e “prendere in prestito iteratore” semantica.

Dimostrato dalle implementazioni di HashMap IntoIterator. (Usano le strutture iteratore di hashmap Iter e IntoIter.) Ciò che è interessante qui è che il tratto è implementato per il tipo &HashMap<K, V, S> per esprimere il "prestito iteratore".

impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> 
    where K: Eq + Hash, S: HashState 
{ 
    type Item = (&'a K, &'a V); 
    type IntoIter = Iter<'a, K, V>; 

    fn into_iter(self) -> Iter<'a, K, V> { 
     self.iter() 
    } 
} 

impl<K, V, S> IntoIterator for HashMap<K, V, S> 
    where K: Eq + Hash, S: HashState 
{ 
    type Item = (K, V); 
    type IntoIter = IntoIter<K, V>; 

    /// Creates a consuming iterator, that is, one that moves each key-value 
    /// pair out of the map in arbitrary order. The map cannot be used after 
    /// calling this. 
    fn into_iter(self) -> IntoIter<K, V> { 
     /* ... */ 
    } 
} 
1

basato su un altro question, ho pensato che il modo migliore per farlo sarebbe quello di definire l'Iterator come un tipo caratteristica, in questo modo:

pub trait TraitA<'a> { 
    type I1: Iterator<Item=u8>; 
    type I2: Iterator<Item=&'a u8>; 

    fn iter_i1(&self) -> Self::I1; 
    fn iter_i2(&self) -> Self::I2; 
} 

fn foo<'a, A: TraitA<'a>>(a: &A) { 
    for x in a.iter_i1() { } 
    for x in a.iter_i2() { } 
} 
Problemi correlati