如何指定特征的所有实现者也必须实现序列化?

How to specify that all implementers of a trait must also implement Serialize?

我很想知道通过内置反射可以节省多少样板文件。

一点背景知识

结构化日志背后的我的想法是使用各种小型定制类型将内容与表示分开。而不是非结构化 logger.info("Found a bar with {} foos", bar.foo) 一个使用像 logger.info(FoundBar{ _bar: bar })

我的 Rust-ish 方法

定义特征,提供默认实现:

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),但除此之外,让 Serde 泄漏的实现细节似乎是个坏主意 (TM)进入我的代码。

如何可移植地限制我的特征(使用 where?)仅适用于具有正确派生的类型?更好的是,我可以 "inject" 使用特征将功能派生到类型中吗?

如果您创建 MCVE of your problem on the playground,您会得到更准确的错误:

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`

按照建议,但使用惯用的 supertrait 语法,回答您的问题:

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

另请参阅:

使用特征继承有效,但使用正确的 Serde 特征,而不是编译器建议的特征:

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