2016-05-26 9 views
1

Ich habe ein Programm, bei dem Benutzereingaben in einer Funktion gesammelt und ein Wert zurückgegeben wird. In der Funktion versucht es, den String Eingang zu einem u32 zu analysieren. Wenn es fehlschlägt, anstatt Panik und beenden Sie das Programm, ich möchte es die String zurückgeben.Wie gebe ich einen benutzerdefinierten Typ bei Erfolg oder eine Zeichenfolge bei einem Fehler zurück?

Ist es möglich, einen beliebigen Rückgabetyp zuzulassen? Ich las den Generikaabschnitt im Rust Book, aber es enthielt nichts über die Rückgabe eines generischen Typs.

Hier ist mein Code:

fn read_input(question: &str) -> u32 { 
    let mut input = String::new(); 
    println!("{}", question); 
    io::stdin() 
     .read_line(&mut input) 
     .ok() 
     .expect("failed to read input"); 
    match input.trim().parse() { 
     Ok(number) => { 
      return number; // return a u32 
     } 
     Err(_) => { 
      return input; // return a String 
     } 
    } 
} 

Antwort

5

Es scheint, dass Sie zwei verschiedene Fragen hier fragen.

1. Wie kann der Benutzer den Ausgabetyp einer Funktion angeben?

Verwenden Sie einen generischen Parameter. Zum Beispiel benötigt die Iterator::collect einen Typparameter B, der als Rückgabetyp verwendet wird.

2. Wie kann ich einen Wert zurückgeben, der aus zwei verschiedenen Typen bestehen kann?

Sie können ein enum erstellen, die als die „Vereinigung“ der beiden Arten dienen:

pub enum Union<A, B> { 
    ValueA(A), 
    ValueB(B) 
} 

In diesem Fall gibt es für den ValueA oder ValueB Fall keine intrinsische Bedeutung ist.

Die Result Enum ist dies ähnlich, aber es fügt jeden Fall Sinn, das heißt, der Ok Fall zeigt Erfolg und Err zeigt einen Fehler an.


Das heißt, schlage ich vor, dass Sie Result und dass der Fehlerfall gibt die Leseeingang mit dem parse Fehler verwenden:

use std::io; 
use std::str::FromStr; 

// 1: T is a type parameter that is used as (part of) return type 
// 
// 2: Result allows you to return either the parsed T value or 
// the read input value with the parse error 
fn read_input<T: FromStr>(question: &str) -> Result<T, (String, T::Err)> { 
    let mut input = String::new(); 
    println!("{}", question); 
    io::stdin() 
     .read_line(&mut input) 
     .ok() 
     .expect("failed to read input"); 
    match input.trim().parse() { 
     Ok(p) => Ok(p), 
     Err(err) => Err((input, err)) 
    } 
} 

Dies ermöglicht Ihnen eine schöne Fehlermeldung an den Benutzer zu schreiben :

fn main() { 
    // you can use any type that implements FromStr instead of u32 
    match read_input::<u32>("2 + 2?") { 
     Ok(ans) => println!("answer: {}", ans), 
     Err((input, err)) => println!("\"{}\" is an invalid answer: {}", input, err) 
    } 
} 
+0

Vielen Dank. Das hat meine Frage (n) perfekt beantwortet. – qolop

0

Es scheint mir, dass das, was zu tun für diese spezielle Funktion der Result aus der input.trim().parse() Linie zurück. Das Verfahren kann auch generisch gemacht werden, wie Sie sagen, das Ergebnis von etwas zurückzugeben, die parse-able ist see docs

fn read_input<F>(question: &str) -> Result<F, F::Err> 
    where F : FromStr 
    { 
    let mut input = String::new(); 
    println!("{}", question); 
    io::stdin() 
     .read_line(&mut input) 
     .expect("failed to read input"); 
    input.trim().parse() 
} 

Siehe playground und gist

+0

'ok(). Expect()' ist schlecht, es wirft die Information in dem 'Result :: Err' weg. Verwenden Sie '.read_line(). Expect()'. – delnan

+0

danke, aktualisiert, um das zu reflektieren – user25064