Rust Utilizzo avanzato di println!


Esempio

println! (e suo fratello, print! ) fornisce un pratico meccanismo per la produzione e la stampa di testo che contiene i dati dinamici, simili al printf famiglia di funzioni che si trovano in molte altre lingue. Il primo argomento è una stringa di formato , che stabilisce come gli altri argomenti devono essere stampati come testo. La stringa di formato può contenere segnaposti (racchiusi in {} ) per specificare che si dovrebbe verificare una sostituzione:

// No substitution -- the simplest kind of format string
println!("Hello World");
// Output: Hello World

// The first {} is substituted with a textual representation of
// the first argument following the format string. The second {}
// is substituted with the second argument, and so on.
println!("{} {} {}", "Hello", true, 42);
// Output: Hello true 42

A questo punto, potresti chiederti: come ha fatto println! sapere di stampare il valore booleano true come la stringa "true"? {} è in realtà un'istruzione al formattatore che il valore dovrebbe essere convertito in testo usando il tratto Display . Questo tratto è implementato per la maggior parte dei tipi di ruggine primitivi (stringhe, numeri, booleani, ecc.) Ed è pensato per "output rivolto all'utente". Quindi, il numero 42 verrà stampato in decimale come 42, e non, per esempio, in binario, che è il modo in cui viene memorizzato internamente.

Come si stampano i tipi, quindi, che non implementano Display , gli esempi sono Slices ( [i32] ), i vettori ( Vec<i32> ) o le opzioni ( Option<&str> )? Non esiste una rappresentazione testuale chiara di questi utenti (cioè una che potresti inserire banalmente in una frase). Per facilitare la stampa di tali valori, Rust ha anche il tratto Debug e il segnaposto {:?} Corrispondente. Dalla documentazione: " Debug dovrebbe formattare l'output in un contesto di debugging del programmatore." Vediamo alcuni esempi:

println!("{:?}", vec!["a", "b", "c"]);
// Output: ["a", "b", "c"]

println!("{:?}", Some("fantastic"));
// Output: Some("fantastic")

println!("{:?}", "Hello");
// Output: "Hello"
// Notice the quotation marks around "Hello" that indicate
// that a string was printed.

Debug ha anche un meccanismo incorporato di stampa carina, che puoi abilitare usando il modificatore # dopo i due punti:

println!("{:#?}", vec![Some("Hello"), None, Some("World")]);
// Output: [
//    Some(
//        "Hello"
//    ),
//    None,
//    Some(
//        "World"
//    )
// ]

Le stringhe di formato consentono di esprimere sostituzioni piuttosto complesse :

// You can specify the position of arguments using numerical indexes.
println!("{1} {0}", "World", "Hello");
// Output: Hello World

// You can use named arguments with format
println!("{greeting} {who}!", greeting="Hello", who="World");
// Output: Hello World

// You can mix Debug and Display prints:
println!("{greeting} {1:?}, {0}", "and welcome", Some(42), greeting="Hello");
// Output: Hello Some(42), and welcome

println! e gli amici ti avvertiranno anche se stai provando a fare qualcosa che non funziona, piuttosto che a crash in fase di runtime:

// This does not compile, since we don't use the second argument.
println!("{}", "Hello World", "ignored");

// This does not compile, since we don't give the second argument.
println!("{} {}", "Hello");

// This does not compile, since Option type does not implement Display
println!("{}", Some(42));

Al loro centro, le macro di stampa Rust sono semplicemente wrapper in tutto il format! macro, che consente di costruire una stringa cucendo insieme rappresentazioni testuali di diversi valori di dati. Quindi, per tutti gli esempi sopra, puoi sostituire println! per il format! per memorizzare la stringa formattata invece di stamparla:

let x: String = format!("{} {}", "Hello", 42);
assert_eq!(x, "Hello 42");