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

时间:2018-11-26 20:11:12

标签: rust serde

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

一些背景

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

我的生锈方法

  • 定义Log特质
  • 提供一个默认的实现,该实现调用Serde机械以序列化类型(在此示例中为JSON)
  • 通过让它们“继承”默认实现轻松定义可记录类型
  • 利润

定义特征,提供默认的隐含值:

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`

在我的trait函数中添加where Self建议只会产生不同的错误(error[E0433]: failed to resolve. Use of undeclared type or module _IMPL_DESERIALIZE_FOR_Message),但除此之外,将Serde的实现细节泄漏到我的账户中似乎是一个坏主意(TM)代码。

如何便携地约束我的特征(使用where?)仅适用于具有正确派生的类型?更好的是,我可以使用特征将派生功能“注入”到类型中吗?

2 个答案:

答案 0 :(得分:2)

如果您创建MCVEyour 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`

遵循建议,但使用惯用的超特征语法,可以回答您的问题:

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

另请参阅:

答案 1 :(得分:1)

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

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