Lost trying to use Debug/Display traits for user-defined formatting


#1

Hi all,

Is it possible to code user-defined formatting options (like in special Python formatting method).
I’d like for example to be able to:

println!("{html}", myStruct) ;

to print out HTML table containing myStruct data. Or:

println!("{csv}", myStruct) ;

Is it possible to implement that ?

Thanks for your help.


#2

Yes it is possible. You need to use println!("{}", Html(my_struct)) rather than println!("{html}", my_struct).

use std::fmt::{self, Display};
use std::ops::Deref;

struct S {
    content: &'static str,
}

struct Html<T>(T);

impl<T> Deref for Html<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Display for Html<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<s>{}</s>", self.content)
    }
}

fn main() {
    let my_struct = S { content: "dandyvica" };
    println!("{}", Html(my_struct));
}

A concrete example of this from the standard library is char::to_uppercase which returns a struct implementing Display.

println!("{}", 'ß');
println!("{}", 'ß'.to_uppercase());

#3

Thanks dtolnay. I thought it could be easier, but I’ll keep that as an example to implement it !


#4

Anyway, what’s the advantage over implementing:

fn as_html(&self) {}

?

As I understand it, depending on the format string, the corresponding trait (e.g.:{:?} calls Debug)
will be called. Is it possible to imagine a proposal where for example:

println!("{?myformat}", myStruct}

will call a specific trait by also passing the format string ?


#5

You can put three of “´” before and three after your code.


#6

Great advice, thanks !


#7

If Html is a typical temporary wrapper, I’d construct it so that you use Html(&s) to format something with it. (I.e a reference to your type). Then it’s easy to use temporarily and you don’t need to care about ownership or moving it out again.

(This is only relevant for the impl Display for Html<S> part, which you’d change a bit to implement it for Html<&'a S> for all 'a instead).


#8

@dandyvica One advantage to implementing Display is that it’s easily recursively composable, without having to allocate any temporary strings for each piece. Its overhead is the format-related overhead (virtual function calls) and that’s it.


#9

Sorry, but I love the

object.__format__(self, format_spec)

special method from Python 3 !

But your solution is also elegant.