简体   繁体   中英

Print all struct fields in Rust

I have around 10 structs with between 5-10 fields each and I want to be able to print them out using the same format.

Most of my structs look like this:

struct Example {
  a: Option<String>,
  b: Option<i64>,
  c: Option<String>,
  ... etc
}

I would like to be able to define a impl for fmt::Display without having to enumerate the fields again so there is no chance for missing one if a new one is added.

For the struct:

let eg = Example{
  a: Some("test".to_string),
  b: Some(123),
  c: None,
}

I would like the output format:

a: test
b: 123
c: -

I currently am using #[derive(Debug)] but I don't like that it prints out Some(X) and None and a few other things.

If I know that all the values inside my structs are Option<T: fmt::Display> can I generate myself a Display method without having to list the fields again?

This may not be the most minimal implementation, but you can derive serialisable and use the serde crate. Here's an example of a custom serialiser: https://serde.rs/impl-serializer.html

In your case it may be much simpler (you need only a handful of types and can panic/ignore on anything unexpected).

Another approach could be to write a macro and create your own lightweight serialisation solution.

I ended up solving this with a macro. While it is not ideal it does the job.

My macro currently looks like this:

macro_rules! MyDisplay {
    ($struct:ident {$( $field:ident:$type:ty ),*,}) => {
        #[derive(Debug)]
        pub struct $struct { pub $($field: $type),*}

        impl fmt::Display for $struct {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                $(
                    write!(f, "{}: {}\n",
                        stringify!($field).to_string(),
                        match &self.$field {
                            None => "-".to_string(),
                            Some(x) => format!("{:#?}", x)
                        }
                    )?;
                )*
                Ok(())
            }
        }
    };
}

Which can be used like this:

MyDisplay! {
    Example {
        a: Option<String>,
        b: Option<i64>,
        c: Option<String>,
    } 
}

Playground with an example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=cc089f8aecaa04ce86f3f9e0307f8785

My macro is based on the one here https://stackoverflow.com/a/54177889/1355121 provided by Cerberus

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM