Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement the ToString trait to create a comma-delimited string without a trailing comma?

Tags:

rust

I have this code:

struct A {
    names: Vec<String>,
}

impl ToString for A {
    fn to_string(&self) -> String {
        // code here
    }
}

fn main() {
    let a = A {
        names: vec!["Victor".to_string(), "Paul".to_string()],
    };
    println!("A struct contains: [{}].", a.to_string());
}

Expected output:

A struct contains: [Victor, Paul].

What is the best way to implement this trait to achieve the goal? I have tried some weird 'for each' and other variants, but each one gives me a trailing comma like this:

Victor, Paul,

Of course I can pop it off later, but I am interested in the language so I want to know the best practice of this. This is just an example of what I've tried, but it does not matter, I am asking how to do this most efficiently.

like image 243
Victor Polevoy Avatar asked May 22 '16 11:05

Victor Polevoy


1 Answers

According to the ToString documentation:

This trait is automatically implemented for any type which implements the Display trait. As such, ToString shouldn't be implemented directly: Display should be implemented instead, and you get the ToString implementation for free.

You can implement Display like this:

use std::fmt;

impl fmt::Display for A {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let mut str = "";
        for name in &self.names {
            fmt.write_str(str)?;
            fmt.write_str(name)?;
            str = ", ";
        }
        Ok(())
    }
}

And you don't need to call to_string (but you can):

fn main() {
    let a = A {
        names: vec!["Victor".to_string(), "Paul".to_string()],
    };
    println!("A struct contains: [{}].", a);
}

Note the purpose of the Display:

Display is similar to Debug, but Display is for user-facing output, and so cannot be derived.

If your intent is debug, you can derive Debug:

#[derive(Debug)]
struct A {
    names: Vec<String>,
}

fn main() {
    let a = A { names: vec![
        "Victor".to_string(),
        "Paul".to_string(),
    ]};
    // {:?} is used for debug
    println!("{:?}", a);
}

Outputs:

A { names: ["Victor", "Paul"] }

The Formatter struct offers a rich collections of methods, so you can write your own Debug implementation:

impl fmt::Debug for A {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.debug_struct("A")
           .field("names", &self.names)
           .finish()
    }
}
like image 90
malbarbo Avatar answered Sep 20 '22 22:09

malbarbo