【问题标题】:implementation of Serde::Deserialize is not general enoughSerde::Deserialize 的实现不够通用
【发布时间】:2021-06-28 00:36:57
【问题描述】:

我在我的应用程序中使用event_emmiter_rs 进行事件处理。该库允许您订阅带有回调的事件并触发这些事件。事件采用 (strings, value) 的形式,回调采用采用 value 参数的闭包形式。通过事件回调发送的值必须实现 Serde::Deserialize。 We can see this here in the docs。所以我创建了这个简单的设置:

use event_emitter_rs::EventEmitter;
use serde::Serialize;
use serde::Deserialize;
use std::borrow::Cow;

#[derive(Clone, Serialize, Deserialize, Debug)]
#[serde(bound(deserialize = "'de: 'static"))]
//#[serde(bound(deserialize = "'de: 'a"))] using the 'a lifetime gives same error
pub struct DraggableInfo<'a>{
    parent: WidgetValue<'a>,
    index: WidgetValue<'a>,
    draggable_id: WidgetValue<'a>,
}

impl<'a> DraggableInfo<'a>{
    pub fn new(parent: &'static str, index: u32, draggable_id: &'static str)->Self{
        DraggableInfo{
            parent: WidgetValue::CString(Cow::Borrowed(parent)),
            index: WidgetValue::Unsized32(index),
            draggable_id: WidgetValue::CString(Cow::Borrowed(draggable_id)),
        }
    }
}

#[derive(Clone, Serialize, Deserialize, Debug)]
pub enum WidgetValue<'a>{
    Integer32(i32),
    Unsized32(u32),
    CString(Cow<'a, str>)
}

fn main(){
    let mut event_emitter = EventEmitter::new();
    event_emitter.on("Print Draggable Value", |dragValue: DraggableInfo| {dbg!(dragValue);});
    event_emitter.emit("Print Draggable Value", DraggableInfo::new("root", 0, "layer 1")); 
}

但这会导致错误消息:

error: implementation of `Deserialize` is not general enough
  --> src\main.rs:34:19
   |
34 |     event_emitter.on("Print Draggable Value", |dragValue: DraggableInfo| {dbg!(dragValue);});
   |                   ^^ implementation of `Deserialize` is not general enough
   |
   = note: `DraggableInfo<'_>` must implement `Deserialize<'0>`, for any lifetime `'0`...
   = note: ...but `DraggableInfo<'_>` actually implements `Deserialize<'1>`, for some specific lifetime `'1`

我不确定该消息所指的 Deserialize&lt;'0&gt;Deserialize&lt;'1&gt; 生命周期是什么,或者当编译器说 impl “太笼统”时,它的确切含义是什么。我该如何解决这个错误?

【问题讨论】:

  • 由于de: 'static 的限制,它不够通用。这意味着您只能从静态数据(即在程序的整个生命周期中存在的数据)进行反序列化。大概event_emitter 处理比这更短的数据,这就是它抱怨的原因。
  • 我认为这也可能是这种情况,但使用 #[serde(bound(deserialize = "'de: 'a"))] 会出现同样的错误。
  • 嗯,这仍然是一个约束。我不熟悉您使用的箱子,但您可能需要这些结构来拥有它们的数据,因为错误很明显,该类型需要在 any 生命周期内实现 Deserialize。跨度>
  • 我不太确定在这种情况下结构拥有它的数据意味着什么。我对生命的理解很差。您能否向我指出一篇说明您的建议的相关文章/答案?
  • 我的意思是使用String 而不是Cow&lt;'a, str&gt;

标签: rust serde


【解决方案1】:

问题在 cmets 中被驳回,但您的具体问题在这一行中很突出:

#[serde(bound(deserialize = "'de: 'static"))]

正如Serde guide 预警:

请注意,&lt;T&gt; where T: Deserialize&lt;'static&gt; 绝不是您想要的。 Deserialize&lt;'de&gt; + 'static 也永远不是你想要的。通常在Deserialize 附近的任何地方写'static 都是走错路的标志。请改用上述边界之一。

这应该具有实际意义:您永远都不想从 100% 静态数据中反序列化。你拥有的那些WidgetValues,它们会在运行时动态地进出范围(被创建/销毁),对吧?..

但是,当您将带有 referenceCString 变体定义到原始输入缓冲区(发生反序列化的事件负载)中时 - 您必须确保没有一个 WidgetValue 永远存在它的输入缓冲区。这就是 Rust 生命周期的用途,它们编码机器检查的保证,即 Bad Things™ 不会发生。

再次来自 cmets:简单的解决方案是拥有数据,而不是借用(引用)它,即

pub enum WidgetValue {
    Integer32(i32),
    Unsized32(u32),
    CString(String),
}

...但是这种简单性会让您付出性能成本,在堆分配和无偿字符串复制中,每当WidgetValues 被传递时。您将失去 Serde 支持的 zero-copy capacity。并不是说它本质上是坏的;也许这个价格适合您的应用程序。

但是,许多程序员选择 Rust 用于那些性能很重要的应用程序。在不妥协安全的情况下,也是。也就是说:让我们动手吧。


注意:Unsized32 是矛盾的,你可能想写成Unsigned32

注意:在DraggableInfo::new签名中,为什么要求借用的字符串切片有'static生命周期?这太严格了。只需'a 就足够了。

错误很明显,类型需要在任何生命周期内实现反序列化

确实; .on signature 没有 'de 作为通用参数:

pub fn on<F, T>(&mut self, event: &str, callback: F) -> String where
    T: Deserialize<'de>,
    F: Fn(T) + 'static + Sync + Send, 

这意味着调用者无法选择生命周期。有可能这是无意的,也许可以尝试询问作者或event_emitter_rs库;可能是一个微妙的错误,可能是故意的。

顺便说一句:如果您想使用 serde_json::from_reader 之类的东西在流中真正动态地反序列化 - 这整个零拷贝的努力不会奏效。这在 DeserializeOwned 约束中表达。 the guideFor example when deserializing from an IO stream no data can be borrowed.中也提到了这个事实

在这一点上,我放弃了进一步的研究,因为我在从流中解析 JSON 的上下文中访问了这个问题。这意味着我别无选择,只能做DeserializeOwned(即在我的数据结构中使用拥有的String,而不是&amp;'a str)。这也是有道理的,因为流数据是短暂的,所以借用它根本行不通。

【讨论】:

    猜你喜欢
    • 2021-08-19
    • 2019-11-03
    • 2021-12-11
    • 1970-01-01
    • 2019-07-24
    • 1970-01-01
    • 2019-05-13
    相关资源
    最近更新 更多