我想创建一个行为类似于 的“约束”类型String,但在构造时验证它是否符合某些语法。例如,我们可以创建一个Identifier类似于 a 的类型String,但强制所有字符都匹配[a-zA-Z_]。
特别是,我希望实现通常的特征(Display、Ord等),并且我希望serde::Serialize和 的serde::Deserialize行为与正常的 一样String,只是我们在反序列化时进行验证。
有没有一种惯用的方法可以做到这一点,或者我必须手动实现所有特征?
惯用的方法是创建一个新类型并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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
281 次 |
| 最近记录: |