首页 > 解决方案 > In what scenarios are APIs that don't borrow preferred?

问题描述

Rust has the concepts of ownership and borrowing. If a function doesn't borrow its parameter as a reference, the arguments to that function are moved and will be deallocated once they go out of scope.

Take this function:

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

This function can be called as:

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

let user = build_user(email, username);

Since email and username have been moved, they can no longer be used after build_user was called.

This can be fixed by making the API use borrowed references instead.

With that in mind, which scenarios would one always prefer to not use borrowing when designing APIs?

标签: referencerustmove-semanticsapi-designborrowing

解决方案


这个列表可能并不详尽,但很多时候选择不借用论点是有利的。

Copy1.小类型的效率

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

2.转让所有权

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

3.方法链

如果一组方法都使用self和返回Self,您可以方便地将它们链接在一起,而不需要中间的局部变量。您经常会看到这种方法用于实现构建器。以下是从derive_buildercrate文档中获取的示例:

let ch = ChannelBuilder::default()
    .special_info(42u8)
    .token(19124)
    .build()
    .unwrap();

4. 静态执行不变量

有时,您希望函数使用一个值以保证它不能再次使用,作为在类型级别强制执行假设的一种方式。例如,在futurescrate中,该Future::wait方法使用self

fn wait(self) -> Result<Self::Item, Self::Error> 
where
    Self: Sized,

此签名专门用于防止您调用wait两次。实现不必在运行时检查未来是否已经处于等待状态 - 编译器不会允许这种情况。

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

5. 使克隆对调用者明确

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


推荐阅读