马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
Rust - 接口设计建议之不意外(unsurprising)
书:Rust for Rustaceans
Rust接口设计的原则(建议)
不意外(unsurprising)
- 最少意外原则:
- 接口应尽可能直观(可预测,用户能猜对)
- 至少应该不让人感到惊奇
- 核心思想:
- 让接口可预测:
- 命名
- 实现常用的 Traits
- 人体工程学(Ergonomic)Traits
- 包装类型(Wrapper Type)
命名实践
- 接口的名称,应符合惯例,便于推断其功能
- 例:
- 方法 iter,大概率应将 &self 作为参数,并应该返回一个迭代器(iterator)
- 叫做 into_inner 的方法,大概率应将 self 作为参数,并返回某个包装的类型
- 叫做 SomethingError 的类型,应实现 std::error::Error,并出现在各类 Result 里
- 将通用/常用的名称依然用于相同的目的,让用户好猜、好理解
- 推论:同名的事物应该以相同的方式工作
- 遵循 as_, to_, into_ 规范 用以特定类型转换
名称前缀内存代价所有权as_无代价borrowed -> borrowedto_代价昂贵borrowed -> borrowed borrowed -> owned (非 Copy 类型) owned -> owned (Copy 类型)into_视情况而定owned -> owned (非 Copy 类型)实现常用的 Trait
- 用户通常会假设接口中的一切均可“正常工作”,例:
- 使用 {:?} 打印任何类型
- 可发送任何东西到另外的线程
- 期望每个类型都是 Clone 的
- 建议积极实现大部分标准 Trait,即使不立即用到
- 用户无法为外部类型实现外部的 Trait
Rust 的 trait 系统坚持 孤儿原则 :大致说的是, 每个 impl 块必须
- 要么存在于定义 trait 的 crate 中,
- 要么存在于给类型实现 trait 的 crate 中。
所以,定义新类型的 crates 应该尽早实现所有合适的、常见的 traits 。
std 中可给类型实现的、最重要的、常见的 traits 有:
给类型实现 Default trait 和空的 new 构造函数是常见和有必要的。
new 是 Rust 中常规的构造函数,所以不使用参数来构造基本的类型时, new 对使用者来说就理应存在。
default 方法功能上与 new 方法一致,所以也应当存在。
建议实现 Debug Trait
- 几乎所有的类型都能、应该实现 Debug
- #[derive(Debug)],通常是最佳实现方式
- 注意:派生的 Trait 会为任意泛型参数添加相同的约束(bound)
- 利用 fmt::Formatter 提供的各种 debug_xxx 辅助方法手动实现
- debug_struct
- debug_tuple
- debug_list
- debug_set
- debug_map
例子一- use std::fmt::Debug;
- #[derive(Debug)]
- struct Pair<T> {
- a: T,
- b: T,
- }
- fn main() {
- let pair = Pair {a: 5, b: 10};
- println!("Pair: {:?}", pair); // i32 实现了 Debug Trait 故可以打印出来
- }
复制代码 例子二- use std::fmt::Debug;
- struct Person {
- name: String,
- }
- #[derive(Debug)]
- struct Pair<T> {
- a: T,
- b: T,
- }
- fn main() {
- let pair = Pair {
- a: Person { name: "Dave".to_string() },
- b: Person { name: "Nick".to_string() },
- };
- println!("Pair: {:?}", pair); // 报错 `Person` doesn't implement `Debug` Person 没有实现 Debug Trait
- }
复制代码 例子三
[code]use std::fmt;struct Pair { a: T, b: T,}impl fmt::Debug for Pair { fn fmt(&self, f: &mut fmt::Formatter |