Распечатать все структурные поля в Rust - PullRequest
1 голос
/ 23 октября 2019

У меня есть около 10 структур с 5-10 полями в каждом, и я хочу иметь возможность распечатать их в том же формате.

Большинство моих структур выглядят так:

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

Я бы хотел иметь возможность определить impl для fmt::Display без повторного перечисления полей, чтобы не было возможности пропустить одно, если добавлено новое.

Для структуры:

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

Я хотел бы получить формат вывода:

a: test
b: 123
c: -

В настоящее время я использую #[derive(Debug)], но мне не нравится, что он печатает Some(X) и Noneи несколько других вещей.

Если я знаю, что все значения в моих структурах Option<T: fmt::Display>, могу ли я создать метод Display без необходимости повторного перечисления полей?

Ответы [ 2 ]

5 голосов
/ 23 октября 2019

Возможно, это не самая минимальная реализация, но вы можете получить сериализуемый и использовать ящик serde. Вот пример пользовательского сериализатора: https://serde.rs/impl-serializer.html

В вашем случае это может быть намного проще (вам нужно только несколько типов и вы можете паниковать / игнорировать что-либо неожиданное).

Другойподход может заключаться в написании макроса и создании собственного облегченного решения для сериализации.

1 голос
/ 23 октября 2019

Я решил это с помощью макроса. Хотя он не идеален, он выполняет свою работу.

Мой макрос в настоящее время выглядит следующим образом:

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(())
            }
        }
    };
}

Что можно использовать следующим образом:

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

Игровая площадка спример: https://play.rust -lang.org /? version = stable & mode = debug & edition = 2018 & gist = cc089f8aecaa04ce86f3f9e0307f8785

Мой макрос основан на том, что здесь https://stackoverflow.com/a/54177889/1355121 предоставлено Cerberus

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...