如何将受特征限制的类型传递给 Serde 的 deserialize_with?

How do I pass a type bounded by a trait to Serde's deserialize_with?

满足MyTrait的类型应该传递给deserialize_with指定的deserialize_data。这是我的 sample code:

use serde::{Deserialize, Deserializer}; // 1.0.117
use serde_json; // 1.0.59

type Item = Result<String, Box<dyn std::error::Error + Send + Sync>>;
pub trait MyTrait {
    fn method(ind: &str) -> Item;
}

#[derive(Deserialize)]
pub struct S<T>
where
    T: MyTrait + ?Sized, // intend to pass a type T satisfying `MyTrait` to function `deserialize_data`,
{
    #[serde(deserialize_with = "deserialize_data")]
    //#[serde(bound( deserialize = "T: MyTrait,  for<'de2> T: Deserialize<'de2>" ))]
    pub data: String,
}

fn deserialize_data<'de, D, T>(d: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
{
    let ind = <&str>::deserialize(d).unwrap();
    match T::method(ind) {
        Ok(data) => Ok(data),
        Err(e) => Err(serde::de::Error::custom(format_args!("invalid type."))),
    }
}

struct A;
impl MyTrait for A {
    fn method(_ind: &str) -> Item {
        // to make it simple, return constant
        Ok("method".to_string())
    }
}

fn main() {
    let s = r#"{"data": "string"}"#;
    let ob: S<A> = serde_json::from_str(s).unwrap();
}

编译器抱怨:

error[E0392]: parameter `T` is never used
  --> src/main.rs:10:14
   |
10 | pub struct S<T>
   |              ^ unused parameter
   |
   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`

我确实使用 T,而 PhantomData 帮助不大。 一种明显的方法可能是使用 struct A 及其实现的方法作为 crate 或其他东西,然后导入它们。不幸的是,这不适用于我的情况,所以我试图将结构类型传递给 deserialize_data 并实现它。

要编译代码,您需要:

  • struct S<T> 中使用 T,例如 PhantomData
  • 使用 turbofish 运算符 ::<>.
  • 显式将 T 传递给 deserialize_data
  • deserialize_data()中的T泛型添加适当的trait bounds,例如MyTrait.

例如(playground):

#[derive(Deserialize)]
pub struct S<T>
where
    T: MyTrait + ?Sized,
{
    #[serde(deserialize_with = "deserialize_data::<_, T>")]
    pub data: String,
    marker: std::marker::PhantomData<T>,
}

fn deserialize_data<'de, D, T>(d: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
    T: MyTrait + ?Sized,
{
    // ...
}