1 个不稳定版本
使用旧的 Rust 2015
0.1.0 | 2017年11月29日 |
---|
#2274 在 Rust 模式
632 次每月下载
在 13 个包中使用了 (通过 state_machine_future)
16KB
74 行
rent_to_own
RentToOwn<T>
: 一个包装类型,用于在必要时放弃底层值的所有权。
RentToOwn<T>
有用的情况包括
-
一个函数可能需要条件性地 获取 一些
T
值, -
而这个函数不能通过值传递来获取
T
,并且返回一个Option<T>
来可能将T
值返回,如果它不想拥有所有权。
RentToOwn<T>
解引用 (不可变和可变) 到其内部的 T
值,并额外提供了一个 take
方法,该方法将内部值的所有权放弃给调用者。
在底层,RentToOwn<T>
实质上是一个 Option<T>
,在解引用时会被展开,并调用 Option::take
以获取内部值的所有权。除了使用 Deref
糖语法之外,其关键优势在于通过一些生命周期技巧静态地防止所有解包时的恐慌,这些恐慌可能发生在从 RentToOwn<T>
包装器再次使用后。一旦获取了内部值,借用检查器将确保原始的 RentToOwn<T>
无法再使用。有关详细信息,请参阅 take
方法的文档。
示例
在这个示例中,如果 configure
函数遇到任何错误,我们不希望丢弃 BigExpensiveResource
,而是允许调用者处理错误并重新使用资源。实际上,configure
函数根据是否有 IO 错误有条件地获取 BigExpensiveResource
的所有权。
use rent_to_own::RentToOwn;
use std::io::{self, Read};
use std::fs;
/// This is a big, expensive to create (or maybe even unique) resource, and we
/// want to reuse it even if `configure` returns an error.
struct BigExpensiveResource {
// ...
}
#[derive(Default)]
struct Config {
// ...
}
/// A big, expensive resource that has been properly configured.
struct ConfiguredResource {
resource: BigExpensiveResource,
config: Config,
}
fn read_and_parse_config_file() -> io::Result<Config> {
// ...
}
fn configure<'a>(
resource: &'a mut RentToOwn<'a, BigExpensiveResource>
) -> io::Result<ConfiguredResource> {
// We use normal error propagation with `?`. Because we haven't `take`n the
// resource out of the `RentToOwn`, if we early return here the caller still
// controls the `BigExpensiveResource` and it isn't dropped.
let config = read_and_parse_config_file()?;
// Now we `take` ownership of the resource and return the configured
// resource.
let resource = resource.take();
Ok(ConfiguredResource { resource, config })
}
configure
的调用者是什么样的?它调用 RentToOwn::with
来构建 RentToOwn<BigExpensiveResource>
并使用它调用一个闭包。然后它检查闭包的结果以及 BigExpensiveResource
是否被获取。
在这个示例中,调用者可以从读取或解析配置文件时的任何 IO 错误中恢复,并使用默认配置以及 BigExpensiveResource
。
fn use_custom_configuration_or_default(resource: BigExpensiveResource) -> ConfiguredResource {
// We pass the resource into `with` and it constructs the `RentToOwn`
// wrapper around it and then gives the wrapper to the closure. Finally, it
// returns a pair of an `Option<BigExpensiveResource>` which is `Some` if
// the closure took ownership and `None` if it did not, and the closure's
// return value.
let (resource, result) = RentToOwn::with(resource, |resource| {
configure(resource)
});
if let Ok(configured) = result {
return configured;
}
// Reuse the resource if the closure did not take ownership or else
// reconstruct it if the closure did take ownership. (In this particular
// example, we know that `configure` took ownership if and only if the
// result was `Ok`, but that doesn't hold for all possible examples.)
// Finally, return the configured resource with the default configuration.
let resource = resource.unwrap_or_else(|| BigExpensiveResource::reconstruct());
let config = Config::default();
ConfiguredResource { resource, config }
}
许可证:Apache-2.0/MIT