首页 > 解决方案 > 使用 into_serde 反序列化字符串会使应用程序恐慌

问题描述

我的一个朋友正在尝试使用serde_jsoncrate 反序列化 WebSocket 发送的一些消息。

我们遇到了一个特定的错误,我们设法使用以下代码片段重新创建它:

use serde::{Deserialize, Serialize};

#[derive(Deserialize, Debug)]
struct EffetSer {
    test: String
}

fn main() {
   let test_value = JsValue::from_str("{\"test\": \"value\"}");
   let test_value: EffetSer = test_value.into_serde().unwrap();
   log::error!("WOW : {:?}", test_value);
}

我们的 TOML 有以下依赖:

wasm-bindgen = { version = '0.2.63', features = ['serde-serialize'] }
serde = { version = '1.0', features = ["derive"] }
serde_json = '1.0.55'
js-sys = '0.3.40'

错误如下:

app.js:310 panicked at 'called `Result::unwrap()` on an `Err` value: Error("invalid type: string \"{\\\"test\\\": \\\"value\\\"}\", expected struct EffetSer", line: 1, column: 23)'

任何帮助将不胜感激,因为我们仍在努力理解我们做错了什么以及为什么我们不能反序列化我们的String.

标签: rustwebassemblyserdeserde-json

解决方案


into_serde这个问题很可能是对's 语义的误解。

根据文档,它的工作原理如下:

对此值调用 JSON.stringify,然后将生成的 JSON 解析为任意 Rust 值。

换句话说,它的语义如下:

  • 将 的每个组件转换JsValue为相应的serde内部元素;
  • 从给定的组件树中反序列化所需的类型。

现在,这在我们的案例中意味着什么?好吧,您创建JsValueusing JsValue::from_str,再次根据文档,

创建一个新的 JS 值,它是一个字符串。

因此,JsValue正如您可能假设的那样,here 不是一个对象;它是一个原语 - 一个字符串,恰好具有对象 JSON 表示的形状。然后,当您调用 时from_serde,Serde 将字符串视为 - 不是作为输入,而是作为内部表示,不能转换为对象。


现在,该怎么办?有几种方法可以修复此代码:

  1. 首先也是最明显的:根本不要使用JsValue&str直接使用serde_json::from_str.
  2. 使用js_sys::JSON::parse从字符串中获取类对象JsValue,然后将其转换为EffetSerwith into_serde。这可能效率较低,因为它需要往返JSON::parse并将JSON::serialize字符串转换为对象,然后再转换回字符串。
  3. 编写您自己的方法以直接转换JsValueEffetSer。但是,我不确定这是否可能,因为我无法找到从 JS 对象中提取单个字段的方法。

推荐阅读