2016-06-15 10 views
2

Ich möchte map verwenden, um über ein Array zu iterieren und Sachen pro Gegenstand zu erledigen und die for-Schleife loszuwerden. Ein Fehler, den ich nicht verstehe, blockiert meinen Versuch. Was ich erreichen möchte, besteht darin, einen Vektor von i32 zu durchlaufen und auf sie zu passen, um eine Zeichenkette mit Zeichenkettenliteralen zu bilden und sie dann am Ende zurückzugeben.Wie man auf einem Vec abbildet und eine Schließung mit Musterabgleich in Rust verwendet

Funktion:

pub fn convert_to_rainspeak(prime_factors: Vec<i32>) -> String { 
    let mut speak = String::new(); 
    prime_factors.iter().map(|&factor| { 
     match factor { 
      3 => { speak.push_str("Pling"); }, 
      5 => { speak.push_str("Plang"); }, 
      7 => { speak.push_str("Plong"); }, 
      _ => {} 
     } 
    }).collect(); 
    speak 
} 

fn main() {} 

Ausgang:

error[E0282]: type annotations needed 
    --> src/main.rs:10:8 
    | 
10 |  }).collect(); 
    |  ^^^^^^^ cannot infer type for `B` 

Antwort

4

Iterator::collect ist definiert als:

fn collect<B>(self) -> B 
where 
    B: FromIterator<Self::Item> 

Das heißt, es eine Art gibt, die bis zu dem Anrufer ist. Sie haben die Ausgabe jedoch vollständig ignoriert, so dass sie nicht auf einen Typ schließen kann. Der Code missbraucht collect, wenn er grundsätzlich for verwenden möchte.

In Ihrer "korrigierten" Version (die seither bearbeitet wurde, was diesen Absatz sinnlos macht), sind Sie sehr ineffizient, indem Sie in jeder Iteration eine Zeichenfolge zuweisen. Und Sie brauchen keine explizite Typen, die nicht an der Funktion zu spezifizieren, und Sie sollten eine &[i32] stattdessen akzeptieren:

fn convert_to_rainspeak(prime_factors: &[i32]) -> String { 
    prime_factors.iter() 
     .map(|&factor| { 
      match factor { 
       3 => "Pling", 
       5 => "Plang", 
       7 => "Plong", 
       _ => "", 
      } 
     }) 
     .collect() 
} 

fn main() { 
    println!("{}", convert_to_rainspeak(&[1, 2, 3, 4, 5])); 
} 
+0

_allocating strings_: Soll ich eine Konstante & str verwenden und ihre Variable in der Übereinstimmung verwenden? _what is & {T] _: Tut mir leid, ich habe das vorher nie gesehen - werde das doc suchen aber mybe hast du auch eine gute Erklärung – xetra11

+0

'& [T]' ist [a * slice *] (http: // doc .rust-lang.org/stable/book/primitive-types.html # scheiben); Die offizielle Dokumentation beschreibt sie gut.Ich bin unklar, was du mit der Konstante meinst und sie im 'Spiel' verwendest. Ein String-Literal ist eine Konstante und hat keine Zuweisung. Ihr alter (Pre-Edit) Code hat jedes Element zu einer 'String', nicht zu einer' & str' gemappt und dann zu einer anderen 'String' gesammelt. Ich bezog mich auf die innere 'Zeichenfolge' mit den zusätzlichen Zuweisungen. – Shepmaster

0

paar Minuten später löste ich es mich (jedes Upgrade geschätzt):

pub fn convert_to_rainspeak(prime_factors:Vec<i32>) -> String{ 
    let mut speak:String = prime_factors.iter().map(|&factor| { 
     match factor { 
      3 => {"Pling"}, 
      5 => {"Plang"}, 
      7 => {"Plong"}, 
      _ => {""} 
     } 
    }).collect(); 
    speak 
} 

Das Problem war, dass ich nicht bewusst war, Das .collect() erwartet das Ergebnis der Karte. Ich habe dann prime_factors.iter()... einem String zugewiesen und var Bindings neu angeordnet, so dass es jetzt alles funktioniert.

EDIT: Refactoring redundante Zuweisungen an dem spricht Vektor

1

Der Fehler in diesem Fall ist, dass der Compiler nicht herausfinden können, welche Art Sie collect in ing. Wenn Sie eine Typanmerkung zu collect hinzufügen, dann wird es funktionieren:

pub fn convert_to_rainspeak(prime_factors:Vec<i32>) -> String{ 
    let mut speak = String::new(); 
    prime_factors.iter().map(| &factor| { 
     match factor { 
      3 => {speak.push_str("Pling");}, 
      5 => {speak.push_str("Plang");}, 
      7 => {speak.push_str("Plong");}, 
      _ => {} 
     } 
    }).collect::<Vec<_>>(); 
    speak 
} 

Dies ist jedoch nicht wirklich der idiomatische Weg, dies zu tun. Sie sollten for statt:

pub fn convert_to_rainspeak(prime_factors:Vec<i32>) -> String { 
    let mut speak = String::new(); 
    for factor in prime_factors.iter() { 
     match *factor { 
      3 => speak.push_str("Pling"), 
      5 => speak.push_str("Plang"), 
      7 => speak.push_str("Plong"), 
      _ => {} 
     } 
    } 

    speak 
} 
+0

Ah ok ... Gibt es einen Fall zu verwenden iter(). Map() dann? – xetra11

+0

Warum versuchen Sie '.map()' zu verwenden? –

+0

@ xetra11: 'map' ist zu verwenden, wenn das Ergebnis nicht sofort in einer Sammlung gesammelt wird, um zu vermeiden, dass eine Zwischensammlung entsteht, die weggeworfen wird. –

1

Sie auch flat_map() statt map() nutzen könnten. Auf diese Weise können Sie Option zuordnen und None anstelle einer leeren Zeichenfolge zurückgeben, wenn kein entsprechender Wert vorhanden ist.

fn convert_to_rainspeak(prime_factors: &[i32]) -> String { 
    prime_factors 
     .iter() 
     .flat_map(|&factor| match factor { 
      3 => Some("Pling"), 
      5 => Some("Plang"), 
      7 => Some("Plong"), 
      _ => None, 
     }) 
     .collect() 
} 


fn main() { 
    println!("{}", convert_to_rainspeak(&[1, 2, 3, 7])); 
} 
Verwandte Themen