在哪些情况下优先使用不借用的API?

时间:2018-12-16 15:59:51

标签: reference rust move-semantics api-design borrowing

铁锈具有所有权和借款的概念。如果某个函数不借用其参数作为引用,则该函数的参数将被移动,并且一旦超出范围将被释放。

执行此功能:

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 个答案:

答案 0 :(得分:18)

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

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。该实现无需在运行时进行检查即可查看未来是否已经处于等待状态-编译器将不允许这种情况。

在使用方法链接的构建器时,它还可以防止错误。该设计静态地防止您无序进行操作-创建对象后,您不会意外在构建器上设置字段,因为该构建器被其build方法消耗了。

5。使克隆对呼叫者明确

某些功能需要拥有自己的数据。可以通过接受引用然后在函数内调用clone来强制执行 ,但这可能并不总是理想的,因为它向调用者隐藏了潜在的昂贵克隆操作。接受值而不是引用意味着由调用者来克隆值,或者,如果他们不再需要它,则将其移动。