如何从 RefCell<T> 中借用 T 作为参考?
How to borrow the T from a RefCell<T> as a reference?
有时我有一个 struct
包含一个包含在 RefCell
中的值,我想借用这个值,但我不想做访问函数的签名取决于内部实现。为了让它工作,我需要 return 引用作为 Ref<T>
而不是 &T
.
例如,如果这是我的结构:
use std::cell::RefCell;
pub struct Outer<T> {
inner: RefCell<T>,
}
我可以这样写访问器:
use std::cell::Ref;
impl<T> Outer<T> {
fn get_inner_ref(&self) -> Ref<T> {
self.inner.borrow()
}
}
这很好用。我可以这样使用它:
fn main() {
let outer = Outer { inner: RefCell::new(String::from("hi")) };
let inner: &str = &outer.get_inner_ref();
println!("inner value = {:?}", inner);
}
但是,这会将 Ref
作为 public API 的一部分公开,这将使以后在不破坏向后兼容性的情况下更难更改内部结构。
如果我尝试将签名更改为 return 和 &T
— &Ref<T>
可以强制转换为 — 然后我会收到生命周期错误:
impl<T> Outer<T> {
fn get_inner_ref(&self) -> &T {
&self.inner.borrow()
}
}
错误是:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.inner.borrow()
| ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
17 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 15:5...
--> src/main.rs:15:5
|
15 | / fn get_inner_ref(&self) -> &T {
16 | | &self.inner.borrow()
17 | | }
| |_____^
似乎没有办法解决这个问题,因为错误消息是正确的。代码试图获取对 Ref<T>
的引用,它的持续时间与函数调用一样长。为了完成这项工作,我必须通过 returning 来移出 Ref<T>
本身——就像上面的原始代码一样——而不是对它进行新的引用。
有 可以从技术上解决这个问题,但这是一个更特殊的情况(只获取 RefCell
中的一部分值)并且解决方案似乎过于复杂更简单的情况。
这正是 impl Trait
的目的,它已在稳定的 Rust since version 1.26.
中可用
use std::ops::Deref;
impl<T> Outer<T> {
fn get_inner_ref<'a>(&'a self) -> impl Deref<Target = T> + 'a {
self.inner.borrow()
}
}
Rust 编译器知道 实际的 实现是 Ref<T>
但让您不必显式地编写它,并且此函数的调用者只能使用由提供的功能Deref
特征。
只要您 return 的实际值属于实现 Deref<Target = T>
的类型,您以后可以自由更改该实现而不会破坏使用它的任何代码。例如,您可以 return &T
或 one of several other reference types, including your own custom type, as in the 。
有时我有一个 struct
包含一个包含在 RefCell
中的值,我想借用这个值,但我不想做访问函数的签名取决于内部实现。为了让它工作,我需要 return 引用作为 Ref<T>
而不是 &T
.
例如,如果这是我的结构:
use std::cell::RefCell;
pub struct Outer<T> {
inner: RefCell<T>,
}
我可以这样写访问器:
use std::cell::Ref;
impl<T> Outer<T> {
fn get_inner_ref(&self) -> Ref<T> {
self.inner.borrow()
}
}
这很好用。我可以这样使用它:
fn main() {
let outer = Outer { inner: RefCell::new(String::from("hi")) };
let inner: &str = &outer.get_inner_ref();
println!("inner value = {:?}", inner);
}
但是,这会将 Ref
作为 public API 的一部分公开,这将使以后在不破坏向后兼容性的情况下更难更改内部结构。
如果我尝试将签名更改为 return 和 &T
— &Ref<T>
可以强制转换为 — 然后我会收到生命周期错误:
impl<T> Outer<T> {
fn get_inner_ref(&self) -> &T {
&self.inner.borrow()
}
}
错误是:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:16:10
|
16 | &self.inner.borrow()
| ^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
17 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the method body at 15:5...
--> src/main.rs:15:5
|
15 | / fn get_inner_ref(&self) -> &T {
16 | | &self.inner.borrow()
17 | | }
| |_____^
似乎没有办法解决这个问题,因为错误消息是正确的。代码试图获取对 Ref<T>
的引用,它的持续时间与函数调用一样长。为了完成这项工作,我必须通过 returning 来移出 Ref<T>
本身——就像上面的原始代码一样——而不是对它进行新的引用。
有 RefCell
中的一部分值)并且解决方案似乎过于复杂更简单的情况。
这正是 impl Trait
的目的,它已在稳定的 Rust since version 1.26.
use std::ops::Deref;
impl<T> Outer<T> {
fn get_inner_ref<'a>(&'a self) -> impl Deref<Target = T> + 'a {
self.inner.borrow()
}
}
Rust 编译器知道 实际的 实现是 Ref<T>
但让您不必显式地编写它,并且此函数的调用者只能使用由提供的功能Deref
特征。
只要您 return 的实际值属于实现 Deref<Target = T>
的类型,您以后可以自由更改该实现而不会破坏使用它的任何代码。例如,您可以 return &T
或 one of several other reference types, including your own custom type, as in the