[英]Rust recursive reference to "self" in another struct
I have two Rust structs that implements different methods (A and B), and when I instantiate B, I want this B to have A as a struct member.我有两个实现不同方法(A 和 B)的 Rust 结构,当我实例化 B 时,我希望这个 B 将 A 作为结构成员。
In Go, this can be easily done by在 Go 中,这可以通过以下方式轻松完成
type A struct {
b *B
}
type B struct {
a *A
}
I tried Box or Rc/RefCell but can't figure out.我试过 Box 或 Rc/RefCell 但不知道。
This is basically what I need:这基本上是我需要的:
pub struct A<T: Tester> ...
pub struct B<T: Tester> {
pub a: Box<A<T>>,
}
impl<T> A<T>
where
T: Tester,
{
pub fn run(&self) {
let to_add = B {
a: Box::new(self),
}
}
This question goes deep into the topic of ownership .这个问题深入到所有权的话题中。
You always have to ask yourself: Who owns what?你总是要问自己:谁拥有什么?
In your case, inside the run
function, self
is a non-mutable reference.在您的情况下,在
run
函数中, self
是一个不可变的引用。 That means that the self
object is owned by someone else, and we only borrowed it.这意味着
self
对象由其他人拥有,而我们只是借用了它。
That sadly means that we cannot create a Box
out of it, because that would require us to own self
.可悲的是,这意味着我们不能从中创建一个
Box
,因为这需要我们拥有self
。 (Because Box::new()
takes ownership of the object it is given) (因为
Box::new()
取得了它所给对象的所有权)
So all we can do is pass on the borrowed self
object to the B
object.所以我们所能做的就是将借来的
self
对象传递给B
对象。
Now there is a problem, sadly, which depends on your usecase.可悲的是,现在有一个问题,这取决于您的用例。 Every borrowed object is associated with a lifetime , to make sure the borrow gets returned before the original object gets destroyed.
每个借用的对象都与生命周期相关联,以确保在原始对象被销毁之前返回借用。 And if you create a
B
object that holds a reference to A
, the B
object inherits that lifetime.如果您创建一个包含对
A
的引用的B
对象,则B
对象将继承该生命周期。 It's certainly possible to do so, but manual lifetime management is an advanced topic in Rust because it can be frustrating to deal with.当然可以这样做,但是手动生命周期管理是 Rust 中的一个高级主题,因为处理它可能会令人沮丧。
I'd advise you to read a tutorial on how to manage lifetimes in Rust.我建议您阅读有关如何在 Rust 中管理生命周期的教程。
Just to demonstrate how this could look like:只是为了演示这看起来如何:
use std::marker::PhantomData;
pub trait Tester {}
pub struct A<T: Tester> {
_x: PhantomData<T>,
}
pub struct B<'a, T: Tester> {
pub a: &'a A<T>,
}
impl<T> A<T>
where
T: Tester,
{
pub fn run(&self) {
let to_add = B { a: self };
}
}
Ignore the PhantomData
, that's just a dummy to make a struct compile that has an unused generic.忽略
PhantomData
,这只是使具有未使用泛型的结构编译的虚拟对象。
The to_add
object now has the lifetime of the &self
, so if you try to store it somewhere externally or pass it into a thread or something similar, it will tell you that this creates a problem with its lifetime. to_add
对象现在具有&self
的生命周期,因此如果您尝试将其存储在外部某处或将其传递给线程或类似的东西,它会告诉您这会对其生命周期造成问题。 But of course that all depends on your usecase.但当然,这一切都取决于您的用例。
type A struct {
b *B
}
type B struct {
a *A
}
This construct, in Rust, is almost impossible .在 Rust 中,这种构造几乎是不可能的。 It's called a self-referencial data structure and cannot be managed by Rusts borrow checker.
它被称为自引用数据结构,不能由 Rusts 借用检查器管理。 In its simpler form, you can use
Arc
/ Rc
to each other, which will create a memory leak (which is somewhat solveable with Weak
, but again, many thoughts have to be put into who owns it then).在其更简单的形式中,您可以相互使用
Arc
/ Rc
,这将造成内存泄漏(这在某种程度上可以通过Weak
解决,但同样,必须考虑到谁拥有它)。 In its more complicated form, you need to use raw pointers, Pin
and unsafe
.在更复杂的形式中,您需要使用原始指针
Pin
和unsafe
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.