这个列表可能不是详尽无遗的,但有很多时候选择不借用一个参数会更有优势。
1. 对于小的Copy
类型,效率更高
如果一个类型很小并实现了Copy
,通常复制它比传递指针更有效。引用意味着间接 - 除了必须执行两步才能到达数据外,指针后面的值不太可能被紧密地存储在内存中,因此将其复制到CPU高速缓存中会更慢,例如当您对它们进行迭代时。
2. 转移所有权
当您需要数据保留下来,但当前所有者需要被清理并超出作用域时,您可能需要通过将其移动到其他地方来转移所有权。例如,您可能在函数中有一个局部变量,但将其移动到Box
中,以便可以在函数返回后继续存在。
3. 方法链接
如果一组方法都使用self
并返回Self
,则可以方便地将它们链接在一起,而无需中间本地变量。您经常会看到此方法用于实现生成器。以下示例摘自derive_builder
crate文档:
let ch = ChannelBuilder::default()
.special_info(42u8)
.token(19124)
.build()
.unwrap();
4. 静态地强制不变量
有时候,您希望一个值被函数消耗以保证它不能再次使用,这是在类型级别实施假设的一种方式。例如,在futures
crate中,Future::wait
方法会消耗self
:
fn wait(self) -> Result<Self::Item, Self::Error>
where
Self: Sized,
这个签名特别设计用来防止你调用wait
两次。实现不需要在运行时检查future是否已经处于等待状态——编译器就不允许这种情况。
它还可以在使用方法链构建器时防止错误。设计静态地防止你按顺序做出错误的操作——在创建对象之后,你不能意外地在构建器上设置字段,因为构建器被其build
方法消耗了。
5. 显式地向调用者表示克隆
某些函数需要拥有它们的数据。这可以通过接受引用并在函数内部调用clone
来强制执行,但这可能并不总是理想的,因为它会将潜在昂贵的克隆操作隐藏在调用者中。接受值而不是引用意味着由调用者来克隆该值或者如果他们不再需要它,移动它。
build_user()
将参数移动到结构体User
中。如果您想使用借用编写相同的函数,则无法将它们移动到结构体中,因为您不拥有它们,所以您必须克隆它们(或更改User
的定义以存储借用而不是所有权)。 - Sven Marnachto_owned()
复制字符串才能使其工作,如果你不再需要传入的字符串,则这种方法效率低下。另一方面,如果你编写接受值的函数,则可以自由地传递克隆值,如果仍然需要这些值。 - Sven Marnachto_owned()
和生命周期才能完全理解这个 :) 感谢您的反馈! - Pascal Precht