如何使用包含在 `RefCell` 中的 `BorrowMut`?
How to use `BorrowMut` contained within `RefCell`?
我是 BorrowMut
的忠实粉丝,因为它允许我提供允许获取参数所有权或获取引用的 API。这使它们更易于使用,但对我来说实施起来有点困难 - 这是一个可以接受的权衡,因为许多人的需求超过了少数人的需求:)。
现在我尝试将 BorrowMut
与 RefCell
一起使用,但失败了,因为 borrow_mut()
由 RefMut
和 BorrowMut
实现。但是,RefMut
将优先,阻止我深入到 BorrowMut
.
中包含的实际值
例子
以下代码允许您重现问题 - 目标是在 Client
类型上调用 doit()
:
use std::cell::RefCell;
use std::borrow::BorrowMut;
struct Hub<C> {
client: RefCell<C>
}
impl<C> Hub<C>
where C: BorrowMut<Client> {
fn new(client: C) -> Hub<C> {
Hub {
client: RefCell::new(client)
}
}
fn builder<'a>(&'a self) -> Builder<'a, C> {
Builder {
hub: self
}
}
}
struct Builder<'a, C: 'a> {
hub: &'a Hub<C>
}
impl<'a, C> Builder<'a, C>
where C: BorrowMut<Client> {
fn use_client(self) {
// 1: borrow_mut() of RefCell
// 2: borrow_mut() of BorrowMut()
// but doesn't work, as RefMut returned by 1) always yields RefMut
self.hub.client.borrow_mut().borrow_mut().doit()
}
}
struct Client;
impl Client {
fn doit(&mut self) {
println!("DID IT!!")
}
}
// HUB USAGE
{
let h = Hub::new(Client);
h.builder().use_client();
}
{
let mut c = Client;
let h = Hub::new(&mut c);
h.builder().use_client();
}
这会产生以下错误:
tests/lang.rs:1076:55: 1076:61 error: type `&mut core::cell::RefMut<'_, C>` does not implement any method in scope named `doit`
tests/lang.rs:1076 self.hub.client.borrow_mut().borrow_mut().doit()
你能指出我将如何拨打这个电话吗?这可能吗?
元
✗ rustc --version --verbose
rustc 1.0.0-nightly (3e4be02b8 2015-03-13) (built 2015-03-13)
binary: rustc
commit-hash: 3e4be02b80a3dd27bce20870958fe0aef7e7336d
commit-date: 2015-03-13
build-date: 2015-03-13
host: x86_64-apple-darwin
release: 1.0.0-nightly
你 运行 陷入自动借用规则的不幸副作用中,在这种情况下,几乎总是想要的东西(并且几乎总是明确的)最终变得模棱两可,并且它被选中什么对你来说是错误的方式。如果您将表达式分开并在每一步检查类型,它就会变得更加明显。
第一个 borrow_mut
被解释为 RefCell
上的一种方法,它产生所需的 core::cell::RefMut<'_, C>
。 (它有这样一个内部方法的事实覆盖了这样一个事实,即它可以通过自动引用 self.hub.client
来构造一个 borrow_mut
调用,如果 self
在一个可变槽中,因为稍后在此答案中显示。)问题是第二个 没有调用您想要的 BorrowMut
实现的 borrow_mut
.
当您想调用方法时,在此阶段可能会发生两件事:自动获取引用和自动解除引用。在这种特殊情况下,两者 都会产生一个 borrow_mut
您可以调用的方法:
如果它采用对 RefMut
的可变引用,则它具有 &mut RefMut<'_, C>
,并且 &mut T
实现范围内特征 BorrowMut
它提供了一个方法borrow_mut
,所以你只得到另一个&mut RefMut<'_, C>
,它巩固了这个作为使用的选择。
如果取消引用 RefMut
,那么它可以获得 C
,然后它可以使用 BorrowMut<Client>
实现来满足请求的 borrow_mut
方法调用,产生 &mut Client
.
需要哪个?我不确定规则是否在任何地方定义(尽管如果没有定义它们肯定需要很快),但是可以观察到的是第一个路径被采用:它在尝试取消引用之前尝试自动引用,等等ref_cell_borrow.borrow_mut()
returns 一个 &mut RefMut<'_, C>
而不是一个 &mut Client
.
如果你想让它使用其他行为,你需要显式取消引用 RefMut
;那么自动获取一个可变引用只能获取到C
,这就是你需要的
这是带有类型注释的粗略扩展;您可以尝试分配类型 ()
来检查编译时的错误消息:
let mut ref_cell_borrow: std::cell::RefMut<C> = self.hub.client.borrow_mut();
let client: &mut Client = (*ref_cell_borrow).borrow_mut();
client.doit();
回到紧凑形式,它是(*self.hub.client.borrow_mut()).borrow_mut().doit()
。
我是 BorrowMut
的忠实粉丝,因为它允许我提供允许获取参数所有权或获取引用的 API。这使它们更易于使用,但对我来说实施起来有点困难 - 这是一个可以接受的权衡,因为许多人的需求超过了少数人的需求:)。
现在我尝试将 BorrowMut
与 RefCell
一起使用,但失败了,因为 borrow_mut()
由 RefMut
和 BorrowMut
实现。但是,RefMut
将优先,阻止我深入到 BorrowMut
.
例子
以下代码允许您重现问题 - 目标是在 Client
类型上调用 doit()
:
use std::cell::RefCell;
use std::borrow::BorrowMut;
struct Hub<C> {
client: RefCell<C>
}
impl<C> Hub<C>
where C: BorrowMut<Client> {
fn new(client: C) -> Hub<C> {
Hub {
client: RefCell::new(client)
}
}
fn builder<'a>(&'a self) -> Builder<'a, C> {
Builder {
hub: self
}
}
}
struct Builder<'a, C: 'a> {
hub: &'a Hub<C>
}
impl<'a, C> Builder<'a, C>
where C: BorrowMut<Client> {
fn use_client(self) {
// 1: borrow_mut() of RefCell
// 2: borrow_mut() of BorrowMut()
// but doesn't work, as RefMut returned by 1) always yields RefMut
self.hub.client.borrow_mut().borrow_mut().doit()
}
}
struct Client;
impl Client {
fn doit(&mut self) {
println!("DID IT!!")
}
}
// HUB USAGE
{
let h = Hub::new(Client);
h.builder().use_client();
}
{
let mut c = Client;
let h = Hub::new(&mut c);
h.builder().use_client();
}
这会产生以下错误:
tests/lang.rs:1076:55: 1076:61 error: type `&mut core::cell::RefMut<'_, C>` does not implement any method in scope named `doit`
tests/lang.rs:1076 self.hub.client.borrow_mut().borrow_mut().doit()
你能指出我将如何拨打这个电话吗?这可能吗?
元
✗ rustc --version --verbose
rustc 1.0.0-nightly (3e4be02b8 2015-03-13) (built 2015-03-13)
binary: rustc
commit-hash: 3e4be02b80a3dd27bce20870958fe0aef7e7336d
commit-date: 2015-03-13
build-date: 2015-03-13
host: x86_64-apple-darwin
release: 1.0.0-nightly
你 运行 陷入自动借用规则的不幸副作用中,在这种情况下,几乎总是想要的东西(并且几乎总是明确的)最终变得模棱两可,并且它被选中什么对你来说是错误的方式。如果您将表达式分开并在每一步检查类型,它就会变得更加明显。
第一个 borrow_mut
被解释为 RefCell
上的一种方法,它产生所需的 core::cell::RefMut<'_, C>
。 (它有这样一个内部方法的事实覆盖了这样一个事实,即它可以通过自动引用 self.hub.client
来构造一个 borrow_mut
调用,如果 self
在一个可变槽中,因为稍后在此答案中显示。)问题是第二个 没有调用您想要的 BorrowMut
实现的 borrow_mut
.
当您想调用方法时,在此阶段可能会发生两件事:自动获取引用和自动解除引用。在这种特殊情况下,两者 都会产生一个 borrow_mut
您可以调用的方法:
如果它采用对
RefMut
的可变引用,则它具有&mut RefMut<'_, C>
,并且&mut T
实现范围内特征BorrowMut
它提供了一个方法borrow_mut
,所以你只得到另一个&mut RefMut<'_, C>
,它巩固了这个作为使用的选择。如果取消引用
RefMut
,那么它可以获得C
,然后它可以使用BorrowMut<Client>
实现来满足请求的borrow_mut
方法调用,产生&mut Client
.
需要哪个?我不确定规则是否在任何地方定义(尽管如果没有定义它们肯定需要很快),但是可以观察到的是第一个路径被采用:它在尝试取消引用之前尝试自动引用,等等ref_cell_borrow.borrow_mut()
returns 一个 &mut RefMut<'_, C>
而不是一个 &mut Client
.
如果你想让它使用其他行为,你需要显式取消引用 RefMut
;那么自动获取一个可变引用只能获取到C
,这就是你需要的
这是带有类型注释的粗略扩展;您可以尝试分配类型 ()
来检查编译时的错误消息:
let mut ref_cell_borrow: std::cell::RefMut<C> = self.hub.client.borrow_mut();
let client: &mut Client = (*ref_cell_borrow).borrow_mut();
client.doit();
回到紧凑形式,它是(*self.hub.client.borrow_mut()).borrow_mut().doit()
。