首页 > 数据库 > 数据库开发技术 > Newtypes 设计模式-实用总结
Newtypes设计模式请重点看两个[例程],[例程]写得真的很好,[例程]更精彩。
crate声明的trait(e.g. Display trait)实现于第三方crate定义的type(e.g. Vec<T>)上。从而,低成本地增强一个已有类型,而不是“重新造轮子”。在js中,这类作法比比皆是。rustc类型系统识别一个i32字面量5为5米,而不是5头猪。这样可以杜绝程序计算中出现“5米 + 5头猪”的逻辑错误。crate给第三方type定义一个“薄”包装器类型Wrapper(一般为【元组结构体】)。type作为本地Wrapper私有字段的数据类型。Wrapper实现第三方trait。trait -- 被实现于 --> 本地Wrapper类型 -- 代理 --> 第三方type”。Wrapper实现Deref / DerefMut trait,将其变形为【智能指针】。Deref Coercion,本地Wrapper类型实例能够直接.出第三方type的成员方法与字段。从而,达成【代理】的目的。(tuple) struct(比如,struct Miles(f64);)来n米 + m斤”的错误逻辑,因为rustc会警告类型不匹配。这个作法的弊端就是:trait(比如,std::ops::Add)需要在每个语义化(tuple) struct上都被实现一遍。trait实现代码会被重复多次,因为,无论语义单位是“斤”还是“米”,其标量值的四则运算规则实际都是相同的。std::marker::PhantomData,将代表了语义单位的【泛型类型参数】作为【编译时】的类型标记,而不是【运行时】值。std::marker::PhantomData + newtypes设计模式 = 零(运行时)成本的语义化抽象。(tuple) struct作为【语义-包装类型】。比如,struct SemVal<A, B>(A, PhantomData<B>);。std::marker::PhantomData占位类型标记。(tuple) struct是通用【语义-包装器】。而,所有语义信息都存储在它的泛型类型参数里。(tuple) struct做各种“赋能”std::fmt::Display trait,赋能打印日志输出能力。即,输出有语义类型说明的标量值。PartialEq, PartialOrd trait,赋能【大小比较】能力。Clone, Copy trait,使其如标量值一样具有【复制-语义】,而不是【所有权-转移】。std::ops::Deref / std::ops::DerefMut trait,将其变形成【智能指针】和支持Deref Coercion。std::convert::From trait,赋能不同语义单位之间的标量值换算。比如,英寸<->厘米。unit type。比如,用struct Centimeter;代表厘米。unit type仅只作为【编译时】类型标记(并不会渗入【运行时】),但由于【auto trait扩散规则】,咱们也必须对其做Clone, Copy, PartialEq, PartialOrd trait的派生。否则,【语义-包装类型】将不具有【复制-语义】与【大小比较】能力。let cm1 = SemVal::<_, Centimeter>::new(5.0, PhantomData);rustc推断Centimeter标记(业务逻辑)语义类型,代表5.0是厘米PhantomData实例占位。rust类型系统就会确保.出所有标量类型的成员方法。比如,求【对数】和【弧度换算】等。Newtypes设计模式的分享大约就这些。后续有新的感悟与收获,我再补充。请大家持续关注。原文作者:Rust语言中文社区;如有侵权,请联系管理员删除。