rust - 解决 Rust 中需要相互引用的特征之间的循环依赖

标签 rust

我有两个需要相互引用的结构。由于其他原因,这些结构需要同时绕过借用检查器。所以我在 *mut T 周围有一个包装器来绕过检查器。现在我试图让每个结构都具有第二个结构的泛型类型。

这是一个玩具示例:

use d2simrs::util::internalref::InternalRef;

pub trait Layer3Trait {
    fn foo() {
        println!("TraitA::foo()");
    }
}

pub trait Layer2Trait {
    fn bar() {
        println!("TraitB::foo()");
    }
}

pub struct SimpleLayer2<Layer3T>
    where Layer3T: Layer3Trait
{
    pub layer3: InternalRef<Layer3T>,
}

pub struct SimpleLayer3<Layer2T>
    where Layer2T: Layer2Trait
{
    pub layer2: InternalRef<Layer2T>,
}

pub type Layer2 = SimpleLayer2<Layer3>;
pub type Layer2Ref = InternalRef<Layer2>;

pub type Layer3 = SimpleLayer3<SimpleLayer2<Layer3>>;
pub type Layer3Ref = InternalRef<Layer3>;

InternalRef 的代码是 here

为此我得到了

   |
30 | pub type Layer3 = SimpleLayer3<SimpleLayer2<Layer3>>;
   |                                             ^^^^^^
   |
   = note: ...which again requires computing type of `example2::Layer3`, completing the cycle
note: cycle used when computing type of `example2::Layer2`
  --> examples/network/bypass_borrow/example2.rs:27:32
   |
27 | pub type Layer2 = SimpleLayer2<Layer3>;
   |                                ^^^^^^

我可以以某种方式重新定义某些东西,以便 SimpleLayer2 和 SimpleLayer3 可以相互引用。

最佳答案

Rust 不支持循环泛型类型。如果您有:

pub type Layer2 = SimpleLayer2<Layer3>;
pub type Layer3 = SimpleLayer3<Layer2>;

那么Layer3的具体类型将是:

SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<...>>>>>>>

这是不允许的。


正如评论中所指出的,如果您的设计是没有循环依赖的继承式设计,那将是理想的,因为它显然可以避免此类问题。但如果这不合适,解决此问题的标准方法是使用 Rc/Arc 和特征对象,这也将避免您的内部 *mut T 包装器(如果需要可变性,则使用 RefCell/RwLock):

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

pub struct SimpleLayer2 {
    pub layer3: Weak<RefCell<dyn Layer3>>,
}

pub struct SimpleLayer3 {
    pub layer2: Rc<RefCell<dyn Layer2>>,
}

请参阅这些其他问题以了解其他潜在的想法:

关于rust - 解决 Rust 中需要相互引用的特征之间的循环依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69433749/

相关文章:

macros - 是否可以编写一个计算项目并生成枚举的宏?

rust - 如何设置 (Rust) Rocket API 端点模板响应的 HTTP 状态代码?

rust - 从 GitHub 构建依赖箱时找不到 `Cargo.toml`

memory - 为什么内存地址打印的是{:p} much bigger than my RAM specs?

rust - 如何在没有循环依赖的情况下指定 Rust 中完全包含的结构的生命周期

rust - 为什么我不能使用 Rust tonic 并行发送多个请求?

rust - 使用 `move` 创建闭包时的 LLVM 断言

rust - 是否有将 Cargo 更新到最新官方版本的命令?

rust - 为什么这个命令不能正常运行?

rust - 如何从 Rust 中的标准输入读取和取消读取 Unicode 字符?