2.转让所有权当您需要保留数据,但需要清理当前所有者并超出范围时,您可以通过将其移动到其他地方来转移所有权.例如,您可能在一个函数中有一个局部变量,但将其移动到 Box 中,以便在函数返回后它可以继续存在.3.方法链如果一组方法都消耗self并返回Self,你可以方便地将它们链接在一起,不需要中间局部变量.您会经常看到这种方法用于实现构建器.以下是从 derive_builder crate 文档中获取的示例:let ch = ChannelBuilder::default().special_info(42u8).token(19124).建造().解包();4.静态执行不变量有时,您希望函数使用一个值以保证它不能再次使用,作为在类型级别强制执行假设的一种方式.例如,在 futures crate,Future::wait 方法消耗了self:fn wait(self) ->结果在哪里自我:大小,此签名专门用于防止您两次调用 wait.实现不必在运行时检查未来是否已经处于等待状态 - 编译器不会允许这种情况.它还可以在使用方法链构建器时防止出错.该设计静态地防止您乱序操作 - 在创建对象后您不会意外地在构建器上设置字段,因为构建器被其 build 方法消耗.5.使克隆对调用者明确有些函数需要拥有它们的数据.这可以通过接受一个引用然后在函数内调用clone来强制执行,但这可能并不总是理想的,因为它对调用者隐藏了潜在的昂贵的克隆操作.接受值而不是引用意味着由调用者来克隆该值,或者,如果他们不再需要它,就移动它.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("[email protected]");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? 解决方案 This list may not be exhaustive, but there are plenty of times when it's advantageous to choose not to borrow an argument.1. Efficiency with small Copy typesIf a type is small and implements Copy, it is usually more efficient to copy it around, rather than passing pointers. References mean indirection - apart from having to do two steps to get to the data, values behind pointers are less likely to be stored compactly in memory and therefore are slower to copy into CPU caches, for example if you are iterating over them.2. To transfer ownershipWhen you need data to stick around, but the current owner needs to be cleaned up and go out of scope, you might transfer ownership by moving it somewhere else. For example, you might have a local variable in a function, but move it into a Box so that it can live on after the function has returned.3. Method chainingIf a set of methods all consume self and return Self, you can conveniently chain them together, without needing intermediate local variables. You will often see this approach used for implementing builders. Here is an example taken from the derive_builder crate documentation:let ch = ChannelBuilder::default() .special_info(42u8) .token(19124) .build() .unwrap();4. Statically enforcing invariantsSometimes, you want a value to be consumed by a function to guarantee that it cannot be used again, as a way of enforcing assumptions at the type-level. For example, in the futures crate, the Future::wait method consumes self:fn wait(self) -> Result<Self::Item, Self::Error>where Self: Sized,This signature is specifically designed to prevent you from calling wait twice. The implementation doesn't have to check at runtime to see if the future is already in a waiting state - the compiler just won't allow that situation.It also gives protection from errors when using method-chained builders. The design statically prevents you from doing things out of order - you can't accidentally set a field on a builder after the object is created because the builder is consumed by its build method.5. To make cloning explicit to callersSome functions need to own their data. This could be enforced by accepting a reference and then calling clone within the function, but this may not always be ideal because it hides the potentially expensive clone operation from the caller. Accepting the value rather than a reference means that it's up to the caller to clone the value or, if they no longer need it, move it instead. 这篇关于哪些场景下不借用的 API 是首选?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云! 08-23 06:27