简体   繁体   English

Rust 递归引用另一个结构中的“self”

[英]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 .在更复杂的形式中,您需要使用原始指针Pinunsafe

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM