键入必须符合某种语法的String

问题描述 投票:3回答:1

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

特别是,我希望实现通常的特性(DisplayOrd等),我希望serde::Serializeserde::Deserialize的行为与正常的String一样,除了我们在反序列化时验证。

有没有惯用的方法,或者我必须手动实现所有特征?

rust serde
1个回答
3
投票

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

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.