什么场景下优先使用不借用的API?

In what scenarios are APIs that don't borrow preferred?

Rust 有所有权和借用的概念。如果函数不借用其参数作为引用,则该函数的参数将被移动,一旦超出范围将被释放。

取这个函数:

fn build_user(email: String, username: String) -> User {
    User {
        email: email,
        username: username,
    }
}

这个函数可以这样调用:

let email = String::from("foo@example.com");
let username = String::from("username");

let user = build_user(email, username);

由于 emailusername 已移动,调用 build_user 后将无法再使用它们。

这可以通过让 API 使用借用的引用来解决。

考虑到这一点,在设计 API 时,人们总是希望在哪些情况下不使用借用?

此列表可能并不详尽,但有很多时候选择不借用参数是有利的。

1。小型 Copy 类型

的效率

如果一个类型很小并且实现了 Copy,通常复制它比传递指针更有效。引用意味着间接 - 除了必须执行两个步骤来获取数据之外,指针后面的值不太可能紧凑地存储在内存中,因此复制到 CPU 缓存中的速度较慢,例如,如果您正在迭代他们。

2。转让所有权

当您需要保留数据,但当前所有者需要清理并超出范围时,您可以通过将其移动到其他地方来转移所有权。例如,您可能在函数中有一个局部变量,但将其移动到 Box 中,以便它可以在函数 returned 后继续存在。

3。方法链接

如果一组方法都消耗 self 和 return 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 来强制执行,但这可能并不总是理想的,因为它向调用者隐藏了潜在的昂贵的克隆操作。接受值而不是引用意味着由调用者克隆值,或者如果他们不再需要它,则移动它。