我如何表示可以是Rc <T>或Weak <T>的字段

时间:2019-12-02 16:54:02

标签: rust

我想在struct中添加一个字段,如下所示:

struct Foo<T> {
    bar: Smart<T>
}

其中bar可以是Rc<TWeak<T>,具体取决于Foo不同实例之间的“所有权关系”。除了创建自定义枚举之外,Rust中还有什么惯用的方法来做到这一点吗?

3 个答案:

答案 0 :(得分:2)

  

除了创建自定义枚举以外,Rust中还有什么惯用的方法吗?

就像Rust中的其他大多数“此或该”选择一样,enum 惯用方式。

答案 1 :(得分:2)

彼得的答案表明,stdlib中没有这样的抽象。您可以定义一个小的枚举来处理这两种情况:

use std::rc::{Rc, Weak};

enum MaybeStrong<T> {
    Strong(Rc<T>),
    Weak(Weak<T>),
}

impl<T> MaybeStrong<T> {
    fn get(&self) -> Option<Rc<T>> {
        match self {
            MaybeStrong::Strong(t) => Some(Rc::clone(t)),
            MaybeStrong::Weak(w) => w.upgrade(),
        }
    }
}

struct Foo<T> {
    bar: MaybeStrong<T>
}

impl<T> Foo<T> {
    fn from_weak(inner: Weak<T>) -> Self {
        Self { bar: MaybeStrong::Weak(inner) }
    }

    fn from_strong(inner: Rc<T>) -> Self {
        Self { bar: MaybeStrong::Strong(inner) }
    }

    fn say(&self) where T: std::fmt::Debug {
        println!("{:?}", self.bar.get())
    }
}

fn main() {
    let inner = Rc::new("foo!");
    Foo::from_weak(Rc::downgrade(&inner)).say();
    Foo::from_strong(inner).say();
}

self.bar()将始终返回Some(如果它是由强指针创建的),并且在None悬空的情况下返回Weak。请注意,由于get()首先需要创建自己的Rc,因此该方法无法返回&T(包括Option<&T>),因为该{{1} }可能会晃来晃去。这也意味着&T的所有用户在处理过程中都会对内部值拥有一个很强的计数,从而在任何情况下都可以安全使用。

答案 2 :(得分:2)

这种构造通常被称为“两种”,并且有一个板条箱看起来可以解决一些常见的用例:https://docs.rs/either/1.5.3/either/

那你就可以写

struct Foo<T> {
    bar: Either<Weak<T>, Rc<T>>
}

然后获取Option<Rc<T>>的示例函数可能是:

impl <T> Foo<T> {
  fn get_rc(self) -> Option<Rc<T>> {
     self.bar
       .map_left( |weak| weak.upgrade() )
       .map_right( |v| Some(v) )
       .into_inner()
  }
}

然后可以像这样使用它:

fn main() {
    let x = Rc::new(1);
    let f_direct = Foo{ bar:Either::Right(x.clone()) };
    println!("f_direct.get_rc() = {:?}", f_direct.get_rc());
    let f_weak = Foo{ bar:Either::Left(Rc::downgrade(&x)) };
    println!("f_weak.get_rc() = {:?}", f_weak.get_rc());
}

链接到操场上的完整示例:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=c20faaa46277550e16a3d3b24f3d1750