我想制作一个“约束”类型,其行为类似于String
,但在构造上验证它符合某种语法。例如,我们可能会创建一个Identifier
类型,其行为类似于String
,但强制所有字符都匹配[a-zA-Z_]
。
特别是,我希望实现通常的特性(Display
,Ord
等),我希望serde::Serialize
和serde::Deserialize
的行为与正常的String
一样,除了我们在反序列化时验证。
有没有惯用的方法,或者我必须手动实现所有特征?
惯用的方法是在newtype周围创建一个String
,并得出可以导出的特征。
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);
}