在什么情况下,不借用的API更受欢迎?

Pas*_*cht 9 api-design reference move-semantics rust borrowing

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

采取这个功能:

fn build_user(email: String, username: String) -> User {
    User {
        email: email,
        username: username,
    }
}
Run Code Online (Sandbox Code Playgroud)

此功能可以称为:

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

let user = build_user(email, username);
Run Code Online (Sandbox Code Playgroud)

由于emailusername已被移动,他们不能再被使用之后build_user被调用.

这可以通过使API使用借来的引用来修复.

考虑到这一点,在设计API时,哪些场景总是倾向于不使用借用?

Pet*_*all 19

这个清单可能并不详尽,但有很多时候选择不借用论证是有利的.

1.效率与小Copy类型

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

2.转让所有权

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

3.方法链接

如果一组方法全部消耗self并返回Self,则可以方便地将它们链接在一起,而不需要中间局部变量.您经常会看到这种方法用于实现构建器.以下是从derive_builder包装箱文档中提取的示例:

let ch = ChannelBuilder::default()
    .special_info(42u8)
    .token(19124)
    .build()
    .unwrap();
Run Code Online (Sandbox Code Playgroud)

4.静态强制执行不变量

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

fn wait(self) -> Result<Self::Item, Self::Error> 
where
    Self: Sized,
Run Code Online (Sandbox Code Playgroud)

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

使用方法链式构建器时,它还可以防止错误.该设计静态地阻止您执行任何操作 - 在创建对象后,您不能在构建器上意外设置字段,因为构建器由其build方法使用.

5.使克隆显示给调用者

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