Rust 设计模式:newtype
介绍一种简单但常见的 Rust 设计模式newtype这一模式在 Rust 中很常见也算是一种常识性的术语了。newtype 是指将一个类型比较典型的是基本类型例如 i32, f64, String包裹进一个元组结构体中形成一个新的类型通常会给这个新类型起一个更具有领域含义的名称。例如structEmail(String);这种做法会有以下几点收益 本文原文地址https://laurence.blog.csdn.net/article/details/168145388 1. 避免将参数搞混在下面这个例子中你会注意到amount 和 acc_no 都是整型如果一不注意就容易传错参数fntransfer(amount:i32,acc_no:i32){// something...}fnmain(){letamount:i32500;letacc_no:i326514;// swap args; works ok; incorrect result!transfer(acc_no,amount);}使用 newtype 包裹之后由于有类型检查编译器可以帮助我们检查出这种错误structAmount(i32);structAccNo(i32);// pass structs as argumentsfntransfer(amount:Amount,acc_no:AccNo){// do something}fnmain(){transfer(Amount(500),AccNo(6514));}2. 增加易读性这也是显而易见的下面的示例都能印证这一点structMeters(f64);structCentimeters(f64);structInches(f64);structTotalLength(f64);structNodeIndex(usize);structEdgeIndex(usize);3. 对包裹类型添加校验这也很合理作为特定值时对基类型的格式、取值范围往往是有要求的这些校验、格式化的方法最适合添加在 newtype 上下面的示例是在初始化方法中添加了校验功能structEmail(String);implEmail{// validate when creating Email;pubfnnew(value:String)-ResultSelf,String{ifvalue.contains()value.contains(.){Ok(Email(value))}else{Err(Missing the and/or the ..into())}}}fnmain(){letvalid_emailEmail::new(atlas123.com.to_string());assert!(valid_email.is_ok());}4. 控制可见性 / 隐藏实现细节newtype 的最后一种常见应用场景就是用来控制类型的可见范围。因为 newtype 是用一个新的类型去包裹一个已有的类型利用定义类型时所处的位置在哪个 crate 中以及是否在前面添加 pub 关键字这些差别就可以有效控制类型的可见性。例如下面这个例子pubstructUserName(pubString);// Username is public; String is public too;pubstructPassword(String);// Password is public; String remains hidden;structEmail(String);// Email is only visible in crate.实际上通过控制原始类型和 newtype 类型的可见范围可以创造出更多组合。在下一篇文章中我们将会看到 Zed 项目中的一个真实而有力的 newtype 应用示例在那个实例中就是利用了私有 newtype 公开的 getter / setter 来控制某些全局状态的读写权限请关注本公众号的下一篇文章。最后解释一下使用 newtype 是否会带来额外的开销答案是完全不会。我记得之前我们在《Rust “多态”的来龙去脉(下)dyn Trait ( Trait Object ) 到底是什么东西》一文中介绍过结构体的内存布局根据《Programming Rust, 2nd Edition》第 9 章的介绍Rust 要求结构体的各个字段统一存放在结构体的内存块中每个字段保留其原始数据类型在内存中的布局结构体并不会拆解字段的内存布局不过 Rust 没有对结构体各个字段在内存中的顺序进行明确规定。结构体占据的内存就是它所有字段占据的内存总和结构体本身并不占据额外的内存实际上结构体“类型”在运行时基本不存在字段名、字段类型这些定义只在编译期使用。编译完成后访问字段被翻译成“起始地址 固定偏移量”的内存读写运行时不需要查询任何结构体描述。所以newtype 结构体是零成本的其本身并不会额外占用内存在编译时编译器会生成它的 TypeId这是我们唯一需要的信息只在编译期有用和有效。参考资料https://medium.com/isuru.dex/brief-overview-of-rusts-newtype-design-pattern-8855a44d9e28