第5章 可预测性
4 分钟阅读
译文 · 基于 Rust API Guidelines
原文链接: https://rust-lang.github.io/api-guidelines/predictability.html
可预测性
智能指针不添加固有方法 (C-SMART-PTR)
例如,这就是为何 Box::into_raw 函数如此定义。
| |
若改为定义为固有方法,则在调用处会令人困惑:被调用的究竟是 Box<T> 上的方法,还是 T 上的方法。
| |
转换位于所涉最具体的类型上 (C-CONV-SPECIFIC)
有疑问时,优先使用 to_/as_/into_ 而非 from_,因为它们用起来更符合人体工程学(且可与其他方法链式调用)。
对于许多两种类型之间的转换,其中一种类型明显更“具体”:它提供了另一种类型所不具备的额外不变量或解释。例如,str 比 &[u8] 更具体,因为它是 UTF-8 编码的字节序列。
转换应放在所涉及类型中更具体的那一侧。因此,str 既提供了 as_bytes 方法,也提供了 from_utf8 构造器,用于与 &[u8] 值之间的相互转换。这一约定不仅直观,还能避免用无穷无尽的转换方法污染像 &[u8] 这样的具体类型。
有明确接收者的函数应是方法 (C-METHOD)
对于任何明显与某一特定类型相关联的操作,优先使用
| |
而非
| |
方法相对函数有诸多优势:
- 使用时无需导入或限定:只需拥有适当类型的值。
- 调用时会执行自动借用(包括可变借用)。
- 便于回答“对类型
T的值我能做什么”这一问题(尤其是在使用 rustdoc 时)。 - 提供
self记法,更简洁,也往往更能清晰传达所有权上的区别。
函数不使用输出参数 (C-NO-OUT)
对于返回多个 Bar 值,优先使用
| |
而非
| |
像元组和结构体这样的复合返回类型会被高效编译,且不需要堆分配。若函数需要返回多个值,应通过这类类型之一来完成。
主要例外:有时函数旨在修改调用方已经拥有的数据,例如复用缓冲区:
| |
运算符重载不令人意外 (C-OVERLOAD)
带有内置语法的运算符(*、| 等)可通过实现 std::ops 中的 trait 为某一类型提供。这些运算符伴随强烈的期望:仅当某项运算与乘法有某种相似之处(并共享期望的性质,例如结合性)时才实现 Mul,其他 trait 同理。
只有智能指针实现 Deref 与 DerefMut (C-DEREF)
Deref trait 在许多情形下会被编译器隐式使用,并与方法解析交互。相关规则专门为适配智能指针而设计,因此这些 trait 应仅用于该目的。
标准库中的示例
构造器是静态固有方法 (C-CTOR)
在 Rust 中,“构造器”只是一种约定。围绕构造器命名有多种约定,其间的区分往往很微妙。
最基本的构造器形式是不带参数的 new 方法。
| |
构造器是它们所构造类型的静态(无 self)固有方法。再结合完全导入类型名的做法,这一约定会带来信息丰富而又简洁的构造:
| |
名称 new 一般应用于实例化某一类型的主方法。有时它不带参数,如上面的示例。有时它确实接受参数,例如 Box::new,会传入要放入 Box 中的值。
某些类型的构造器——尤其是 I/O 资源类型——对其构造器使用不同的命名约定,如 File::open、Mmap::open、TcpStream::connect 和 UdpSocket::bind。在这些情况下,名称按领域需要选取。
同一类型往往有多种构造方式。此时常见做法是给次要构造器加上 _with_foo 后缀,如 Mmap::open_with_offset。不过若你的类型有大量构造选项,请考虑改用建造者模式(C-BUILDER)。
有些构造器是“转换构造器”,即从另一类型的已有值创建新类型的方法。它们的名称通常以 from_ 开头,如 std::io::Error::from_raw_os_error。但也要注意十分类似的 From trait(C-CONV-TRAITS)。以 from_ 为前缀的转换构造器与 From<T> 实现之间有三点区别。
from_构造器可以是 unsafe 的;From实现则不行。一个例子是Box::from_raw。from_构造器可以接受额外参数,以消除源数据含义上的歧义,如u64::from_str_radix。- 仅当源数据类型足以确定输出数据类型的编码时,
From实现才合适。当输入只是一堆比特(如u64::from_be或String::from_utf8)时,转换构造器的名称能够标明其含义。
请注意,类型同时实现 Default 与 new 构造器是常见且被期望的。对于两者都有的类型,它们的行为应当一致。任一方都可以用另一方来实现。
标准库中的示例
std::io::Error::new是 IO 错误常用的构造器。std::io::Error::from_raw_os_error是基于从操作系统收到的错误码的转换构造器。Box::new创建新的容器类型,接受单个参数。File::open打开文件资源。Mmap::open_with_offset打开内存映射文件,并带有额外选项。