2016-04-05 5 views
0

Ich versuche, einen Parser zu schreiben, der einen Iterator über einen Vektor an eine Funktion übergibt. Der Code ist ähnlich wie folgt aus:Wie schreibe ich den Typ eines Iterators, der an eine Funktion übergeben wird?

fn foo(itr : ???) { 
    while let Some(c) = itr.next() { 
     if *c != 0 { 
      break; 
     } 
     println!("{}", *c); 
    } 
} 

fn main() { 
    let v = vec![0; 10]; 
    let itr = v.iter(); 
    while let Some(c) = itr.next() { 
     foo(itr); 
    } 
} 

Ich bin nicht sicher, wie die Art des Iterator über den Vektor zu schreiben. Ich habe versucht, den falschen Typ u32 zu setzen, um zu sehen, welcher Typ rustc erwartet: core::slice::Iter<'_, _>. Wenn ich versuche, core::slice rustc zu verwenden, klagt Use of undeclared type or module 'core::slice'

Antwort

3

Es gibt viele Arten von Iteratoren hinzuzufügen; die meiste Zeit, was Sie wirklich wollen, ist eine Funktion, die in der Lage ist, eines von ihnen zu konsumieren. Um dies zu tun, ist die idiomatische Lösung, Generika zu verwenden.

fn foo<'a, T: Iterator<Item=&'a i32>>(mut itr: T) { 
    while let Some(c) = itr.next() { 
     if *c != 0 { 
      break; 
     } 
     println!("{}", *c); 
    } 
} 

fn main() { 
    let v = vec![0; 10]; 
    let mut itr = v.iter(); 
    while let Some(c) = itr.next() { 
     foo(itr); 
    } 
} 

Der obige Code kompiliert nicht obwohl, da es itr in foo bewegt, dann versucht es auf dem while let wieder zu verwenden. Um dies zu lösen, müssen wir den Iterator stattdessen durch Referenz übergeben.

fn foo<'a, T: Iterator<Item=&'a i32>>(itr: &mut T) { 
    while let Some(c) = itr.next() { 
     if *c != 0 { 
      break; 
     } 
     println!("{}", *c); 
    } 
} 

fn main() { 
    let v = vec![0; 10]; 
    let mut itr = v.iter(); 
    while let Some(c) = itr.next() { 
     foo(&mut itr); 
    } 
} 

Statt Generika, können wir auch ein Merkmal-Objekt verwenden:

fn foo<'a>(itr: &mut Iterator<Item=&'a i32>) { 
    while let Some(c) = itr.next() { 
     if *c != 0 { 
      break; 
     } 
     println!("{}", *c); 
    } 
} 

fn main() { 
    let v = vec![0; 10]; 
    let mut itr = v.iter(); 
    while let Some(c) = itr.next() { 
     foo(&mut itr); 
    } 
} 

Das Kapitel über trait objects vom Rust Buch den Unterschied zwischen diesen Lösungen erläutert.

+0

Super! Zu guter Letzt, wenn Sie sich gegenseitig rekursive Funktionen wie in einem rekursiven Descent-Parser haben, wird rost nicht kompiliert, wenn Sie Generika verwenden, aber wenn Sie ein Merkmal-Objekt verwenden, wird es funktionieren. –

0

wurde die Lösung

use std::slice::Iter; 

und der Typ war

fun foo<'a>(itr : &mut Iter<'a, i32>) {} 
+2

Beachten Sie, dass dies nur Ihre Funktion mit Iteratoren vom 'iter()' Methode auf Scheiben, aber nicht mit, sagen wir, 'iter() Karte zurückgegeben werden verwendet, erlauben würde. (| X | ...))' weil es einen anderen Typ hat. Sie müssen hier Generika verwenden, wie @ FrancisGagné es vorschlägt. –

Verwandte Themen