【问题标题】:How to borrow the T from a RefCell<T> as a reference?如何从 RefCell<T> 借用 T 作为参考?
【发布时间】:2018-07-15 15:01:00
【问题描述】:

有时我有一个 struct 包含一个包装在 RefCell 中的值,我想借用该值,但我不想让访问器函数的签名依赖于内部实现.为了使其工作,我需要将引用返回为 Ref&lt;T&gt; 而不是 &amp;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 公开为公共 API 的一部分,这会使以后更难更改内部结构,而不会破坏向后兼容性。

如果我尝试更改签名以返回 &amp;T&amp;Ref&lt;T&gt; 可以强制返回 — 那么我会得到终身错误:

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&lt;T&gt;,它只持续与函数调用一样长。为了完成这项工作,我必须通过返回它来移除 Ref&lt;T&gt; 本身——就像在上面的原始代码中一样——而不是对它进行新的引用。

an answer to How do I return a reference to something inside a RefCell without breaking encapsulation? 可以从技术上解决这个问题,但它是一个更专业的案例(仅获取RefCell 中的一部分值),对于这种更简单的情况,解决方案似乎过于复杂。

【问题讨论】:

    标签: generics reference rust borrow-checker


    【解决方案1】:

    这正是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&lt;T&gt;,但可以避免显式编写它,并且此函数的调用者只能使用 Deref 特征提供的功能。

    只要您返回的实际值是实现Deref&lt;Target = T&gt; 的类型,您就可以在以后随意更改该实现,而不会破坏任何使用它的代码。例如,您可以返回&amp;Tone of several other reference types,包括您自己的自定义类型,如other linked question

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-13
      • 1970-01-01
      • 2019-05-03
      • 1970-01-01
      • 2023-01-20
      • 2020-01-15
      • 2021-05-22
      相关资源
      最近更新 更多