类型的字符串必须符合某些语法

时间:2019-04-11 17:14:52

标签: rust serde

我想制作一个行为类似于String的“受约束”类型,但是在构造上可以验证它是否符合某些语法。例如,我们可以创建一个Identifier类型,其行为类似于String,但强制所有字符都与[a-zA-Z_]匹配。

尤其是,我希望实现通常的特征(DisplayOrd等),并且我希望serde::Serializeserde::Deserialize的行为与正常的String,只是我们在反序列化时会进行验证。

是否有惯用的方式做到这一点,还是我必须手动实现所有特征?

1 个答案:

答案 0 :(得分:3)

惯用的方法是在String周围创建一个newtype并导出可以导出的特征。

For example:

use serde;
use serde_json;

#[derive(
    Eq, PartialEq, Ord, PartialOrd,
    Debug, Default,
    serde::Serialize, serde::Deserialize,
)]
#[serde(transparent)] // to serialize as a string
pub struct Identifier(
    #[serde(deserialize_with = "Identifier::deserialize")]
    String
);

impl Identifier {
    pub fn new(s: String) -> Result<Identifier, &'static str> {
        // do some validation
        if !s.is_empty() && s.contains('a') {
            Ok(Identifier(s))
        } else {
            Err("Not valid")
        }
    }

    fn deserialize<'de, D>(d: D) -> Result<String, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        use serde::de::Error;
        use serde::Deserialize;

        let s = String::deserialize(d)?;
        Identifier::new(s).map(|i| i.0).map_err(D::Error::custom)
    }
}

fn main() {
    let a = Identifier::new("aaa".into()).unwrap();
    let b: Identifier = serde_json::from_str(r#""faaa""#).unwrap();

    println!("{:?}, {:?}", a, b);
    println!("{}", a == b);
}