Как указать, что все реализации черты должны также реализовывать Serialize? - PullRequest
0 голосов
/ 26 ноября 2018

Мне любопытно посмотреть, сколько шаблонной информации можно сэкономить с помощью встроенного отражения.

Небольшой фон

Моя идея, лежащая в основе структурированного ведения журналов, заключается в использовании различных небольших специализированных типов для разделения контентаиз представительства.Вместо неструктурированного logger.info("Found a bar with {} foos", bar.foo) используется что-то вроде logger.info(FoundBar{ _bar: bar })

Мой подход Rust-ish

  • определяет Log черту
  • , обеспечивающую реализацию по умолчанию, котораявызывает механизм Serde для сериализации типа (для JSON в этом примере)
  • позволяет легко определить типы журналируемых объектов, позволяя им «наследовать» реализацию по умолчанию
  • profit

Определите черту, предоставив значение по умолчанию:

trait Log {
    fn to_log(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }
}

(RLS уже рисует злые красные загогулины, но потерпите меня)

Определите простой тип для регистрации:

#[derive(Serialize)]
struct Message {
    msg: String,
}

и пусть он использует реализацию по умолчанию:

impl Log for Message {}

и, наконец, функцию полиморфного ведения журнала, определенную в терминах признака:

fn log(log: &Log) {
    println!("serialized = {}", log.to_log());
}

Компилятор жалуется:

error[E0277]: the trait bound `Self: _IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` is not satisfied
 --> src\main.rs:8:9
  |
8 |         serde_json::to_string(&self).unwrap()
  |         ^^^^^^^^^^^^^^^^^^^^^ the trait `_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` is not implemented for `Self`
  |
  = help: consider adding a `where Self: _IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` bound
  = note: required because of the requirements on the impl of `_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` for `&Self`
  = note: required by `serde_json::ser::to_string`

Добавление предложения where Self к моей функции черты приводит только к различным ошибкам (error[E0433]: failed to resolve. Use of undeclared type or module _IMPL_DESERIALIZE_FOR_Message), но кроме этого кажется плохой идеей (TM), что эта деталь реализации утечки Serde в мойкод.

HКак я могу ограничить свою черту (используя where?), чтобы она применялась только к типам, имеющим правильное наследование?Еще лучше, могу ли я «внедрить» производную функциональность в типы, используя черту?

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Использование наследования черт работает, но использует правильную черту Serde, а не предложенную компилятором:

trait Log: serde::Serialize {
    fn to_log(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }
}
0 голосов
/ 26 ноября 2018

Если вы создадите MCVE из вашей проблемы на игровой площадке , вы получите более точную ошибку:

error[E0277]: the trait bound `Self: serde::Serialize` is not satisfied
 --> src/lib.rs:6:9
  |
6 |         serde_json::to_string(&self).unwrap()
  |         ^^^^^^^^^^^^^^^^^^^^^ the trait `serde::Serialize` is not implemented for `Self`
  |
  = help: consider adding a `where Self: serde::Serialize` bound
  = note: required because of the requirements on the impl of `serde::Serialize` for `&Self`
  = note: required by `serde_json::ser::to_string`

Следуя предложению, но используяСинтаксис идиоматического супертрейта, отвечает на ваш вопрос:

trait Log: serde::Serialize {
    fn to_log(&self) -> String {
        serde_json::to_string(&self).unwrap()
    }
}

Вам потребуется изменить функцию журнала по соображениям безопасности объекта:

fn log(log: &impl Log) {
    println!("serialized = {}", log.to_log());
}

См. также:

...