I'd like to have a field in struct like this:
struct Foo<T> {
bar: Smart<T>
}
在Rust中,如何以惯用方式实现这一点,而无需创建自定义枚举?其中bar可以是Rc<T
或Weak<T>
,具体取决于不同Foo实例之间的“所有权关系”。请注意保留HTML标签。
I'd like to have a field in struct like this:
struct Foo<T> {
bar: Smart<T>
}
在Rust中,如何以惯用方式实现这一点,而无需创建自定义枚举?其中bar可以是Rc<T
或Weak<T>
,具体取决于不同Foo实例之间的“所有权关系”。请注意保留HTML标签。
enum
是惯用的方式。Peter的回答建议,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
,如果是一个 Weak
并且它是悬空的,则返回 None
。请注意,由于 get()
需要先创建一个拥有的 Rc
,该方法无法返回 &T
(包括 Option<&T>
),因为 &T
可能会悬挂。这也意味着在处理过程中,所有使用 bar()
的用户都将拥有一个内部值的强引用计数,使其可以安全地在任何情况下使用。get()
总是意味着内存写入(增加/减少计数器),因此提供一个原地的apply(f: FnOnce(Option<&T>) -> R) -> R
方法可能会很有价值,在Strong
情况下不需要执行这些写入操作。特质限定将需要for<'a>
。 - undefinedstruct 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());
}
在playground中查看完整示例:
注:此链接提供了一个Rust语言的代码示例。
Rc<Child>
),而子对象指向其所有者:Weak<Parent>
。无法区分这种基本差异可能会令人困惑。 - undefined