我有两个用于serde deserialize_with的定制函数

// Converts string to u32
pub fn de_u32_from_str<'de, D>(deserializer: D) -> Result<u32, D::Error>
where
    D: Deserializer<'de>,
{
    let s = String::deserialize(deserializer)?;
    s.parse::<u32>().map_err(de::Error::custom)
}

// Converts string that may be `null` to either `Some(u32)` or `None`
pub fn de_opt_u32_from_opt_str<'de, D>(deserializer: D) -> Result<Option<u32>, D::Error>
where
    D: Deserializer<'de>,
{
    let s = Option::<String>::deserialize(deserializer)?;
    s.map(|s| s.parse::<u32>().map_err(de::Error::custom))
        .transpose()
}

我测试了de_u32_from_str个这样的人:

fn deserialize_u32_from_str(string: &str, expected: u32) {
    let de: StrDeserializer<ValueError> = string.into_deserializer();
    let result = de_u32_from_str(de).unwrap();

    assert_eq!(result, expected);
}

然而,我很难为测试de_opt_u32_from_opt_str创建deserializer

fn deserialize_opt_u32_from_opt_str(maybe_string: Option<&str>, expected: Option<u32>) {
    // I need a `deserializer` here
    let de: ... = ...;
    let result = de_opt_u32_from_opt_str(de).unwrap();

    assert_eq!(result, expected);
}

How can I create a deserializer like

let de: StrDeserializer<ValueError> = string.into_deserializer();

but holding 100to satisfy

let s = Option::<String>::deserialize(deserializer)?;

推荐答案

下面是一个用于Option的反序列化程序,它可以与实现IntoDeserializer的任何类型一起工作(为模仿serde::de::value中的现有实现而构建):

use std::marker::PhantomData;

use serde::de::{Deserializer, Error, IntoDeserializer, Visitor}; // 1.0.160

struct OptionDeserializer<T, E> {
    value: Option<T>,
    marker: PhantomData<E>,
}

impl<T, E> OptionDeserializer<T, E> {
    pub fn new(value: Option<T>) -> Self {
        OptionDeserializer {
            value,
            marker: PhantomData,
        }
    }
}

impl<'de, T, E> Deserializer<'de> for OptionDeserializer<T, E>
where
    T: IntoDeserializer<'de, E>,
    E: Error,
{
    type Error = E;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: Visitor<'de>,
    {
        match self.value {
            Some(value) => visitor.visit_some(value.into_deserializer()),
            None => visitor.visit_none(),
        }
    }

    serde::forward_to_deserialize_any! {
        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
        bytes byte_buf option unit unit_struct newtype_struct seq tuple
        tuple_struct map struct enum identifier ignored_any
    }
}

使用它,函数中缺少的行将是:

let de: OptionDeserializer<&str, ValueError> = OptionDeserializer::new(maybe_string);

查看测试playground的完整演示.

Rust相关问答推荐

为什么父作用域中的变量超出了子作用域

为什么要在WASM库中查看Rust函数需要`#[no_mangle]`?

如何从接收&;self的方法克隆RC

是否有可能同时避免不兼容的不透明类型和代码重复?

如果LET;使用布尔表达式链接(&Q);

如何将像烫手山芋一样不透明的值从一个Enum构造函数移动到下一个构造函数?

为什么铁 rust S的默认排序功能比我对小数组的 Select 排序稍微慢一些?

如何向下转换到MyStruct并访问Arc Mutex MyStruct实现的方法?

作为1字节位掩码的布尔值 struct

如何在 `connect_activate()` 之外创建一个 `glib::MainContext::channel()` 并将其传入?

方法可以被误认为是标准特性方法

如何基于常量在Rust中跳过一个测试

从Rust 的临时文件中创建引用是什么意思?

没有得到无法返回引用局部变量`queues`的值返回引用当前函数拥有的数据的值的重复逻辑

SDL2 没有在终端键上触发?

Rustlings 切片原语

Rust HRTB 是相同的,但编译器说一种类型比另一种更通用

制作嵌套迭代器的迭代器

返回 &str 但不是 String 时,borrow 时间比预期长

为什么一个整型变量赋值给另一个变量后仍然可以使用?