2015-05-19 16 views
27

Ho provato il seguente codice:Come stampare un Vec?

let v2 = vec![1; 10]; 
println!("{}", v2); 

Ma il compilatore si lamenta che:

error[E0277]: the trait bound `std::vec::Vec<{integer}>: std::fmt::Display` is not satisfied 
--> src/main.rs:3:20 
    | 
3 |  println!("{}", v2); 
    |     ^^ trait `std::vec::Vec<{integer}>: std::fmt::Display` not satisfied 
    | 
    = note: `std::vec::Vec<{integer}>` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string 
    = note: required by `std::fmt::Display::fmt` 

Qualcuno implementare questa caratteristica per Vec<T>?

risposta

28

Qualcuno implementa questo tratto per Vec<>?

No.

E sorprendentemente, questa è una risposta corretta dimostrabile; il che è raro dal dimostrare che l'assenza di cose è solitamente difficile o impossibile. Quindi, come possiamo essere così sicuri?

Rust ha molto rigide regole di coerenza, il impl Trait for Struct può essere fatto solo:

  • sia nella stessa cassa come Trait
  • o nella stessa cassa come Struct

e non altrove ; diamo try it:

impl<T> std::fmt::Display for Vec<T> { 
    fn fmt(&self, _: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 
     Ok(()) 
    } 
} 

rendimenti:

error[E0210]: type parameter `T` must be used as the type parameter for some 
       local type (e.g. `MyStruct<T>`); only traits defined in the 
       current crate can be implemented for a type parameter 
--> src/main.rs:1:1 
    | 
1 | impl<T> std::fmt::Display for Vec<T> { 
    |^

Inoltre, per usare un trait, ha bisogno di essere portata (e quindi, si ha bisogno di essere legato alla sua cassa), il che significa che:

  • siete collegati sia con la cassa di Display e la cassa di Vec
  • né implementare Display per Vec

e quindi ci porta a concludere che nessuno implementa Display per Vec.


Come un lavoro in giro, come indicato dalla Manishearth, è possibile utilizzare il Debug tratto, che è richiamabile tramite "{:?}" come di formato.

+0

L'errore E0210 significa che è consentito solo l'implementazione del tratto Display nel file collections/vec.rs? – highfly22

+1

@ highfly22: la mia comprensione è che dovrebbe essere nella stessa cassa, non necessariamente lo stesso file. –

+1

Cosa? Quindi non posso ad-hoc aggiungere un display trait impl nel modulo dove ne ho bisogno per un tipo in un'altra cassa? – BitTickler

37
let v2 = vec![1; 10]; 
println!("{:?}", v2); 

{} è per archi e altri valori che possono essere visualizzati direttamente all'utente. Non c'è un unico modo per mostrare un vettore a un utente, però {:?} può essere utilizzato per eseguire il debug di esso, e che sarà del tipo:

[1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 

Display è il tratto che prevede il metodo dietro {}, e Debug è per {:?}

13

Se si conosce il tipo di elementi contenuti nel vettore, è possibile creare una struttura che utilizzi il vettore come argomento e implementare Display per tale struttura.

use std::fmt::{Display, Formatter, Error}; 

struct NumVec(Vec<u32>); 

impl Display for NumVec { 
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { 
     let mut comma_separated = String::new(); 

     for num in &self.0[0..self.0.len() - 1] { 
      comma_separated.push_str(&num.to_string()); 
      comma_separated.push_str(", "); 
     } 

     comma_separated.push_str(&self.0[self.0.len() - 1].to_string()); 
     write!(f, "{}", comma_separated) 
    } 
} 

fn main() { 
    let numbers = NumVec(vec![1; 10]); 
    println!("{}", numbers); 
} 
+0

Non è necessario conoscere il tipo * esatto * degli elementi; puoi [usare un generico e consentire qualsiasi tipo che implementa 'Display'] (http://play.integer32.com/?gist=38a0d87690419c4c1e7280c95e155d0b&version=stable). – Shepmaster

1

Ecco una battuta, che dovrebbe funzionare anche per voi:

println!("[{}]", v2.iter().fold(String::new(), |acc, &num| acc + &num.to_string() + ", "));

Here è un esempio eseguibile.


Nel mio caso, stavo ricevendo un Vec<&str> da una chiamata di funzione. Non volevo modificare la firma della funzione in un tipo personalizzato (per il quale avrei potuto implementare il tratto Display).

Per il mio unico nel caso, ho potuto attivare la visualizzazione del mio Vec in una battuta che ho usato con println!() direttamente come segue:

println!("{}", myStrVec.iter().fold(String::new(), |acc, &arg| acc + arg)); 

(Il lambda possono essere adattati per l'uso con diversi tipi di dati, o per più concisi implementazioni di tratto Display.)