rust - 是否可以创建一个自定义派生来防止编译时类型之间的循环?

标签 rust

例如,我希望以下代码无法编译,因为 Foo可以指向 Bar可以指向 Foo .

#[derive(NoCycles)]
struct Foo {
    k: u32,
    p: Option<Rc<Bar>>,
}

#[derive(NoCycles)]
struct Bar {
    s: Option<Rc<Foo>>,
}

#[derive(NoCycles)]
struct Baz {
    s: String,
}
Bar已更改为 Option<Rc<Baz>> ,编译应该会成功,因为Foo没有办法指向 Foo .

最佳答案

我没有编写程序宏的经验,但我会尝试为 NoCycle 版本生成一个“平行宇宙”。 IE。对于每个结构 Foo应该参加NoCycle ,会有一个“并行”结构 Foo_NoCycle仅用于循环检测。
现在的想法是:结构 Foo_NoCycle将从 Foo 自动生成,其成员将拥有 NoCycle - Foo中成员的并行类型. IE。以下结构

struct Foo {
    k: u32,
    p: Option<Rc<Bar>>,
}
将有平行 NoCycle结构:
struct Foo_NoCycle {
    k: u32_NoCycle,
    p: Option<Rc<Bar>>_NoCycle, // <- not real rust syntax
}
如您所见,上面的 - simpfy 附加后缀 _NoCycle - 不会导致有效的 Rust 语法。因此,您可以引入一个特征,作为“正常”和 NoCycle 之间的桥梁。 -结构:
trait NoCycleT {
    type NoCycleType;
}
它的用法 - 展示给 Foo_NoCycle - 会是这样的:
struct Foo_NoCycle {
    k: <u32 as NoCycleT>::NoCycleType,
    p: <Option<Rc<Bar>> as NoCycleT>::NoCycleType
}
生成 Foo_NoCycle来自 Foo应该可以通过宏来实现。
现在技巧来了:你告诉 rust 对于 u32对应的NoCycle -类型是 u32 , 而 Rc<Bar>NoCycleBar :
impl NoCycleT for u32 {
    type NoCycle=u32;
}
impl<T: NoCycleT> NoCycleT for Rc<T> {
    type NoCycle = T::NoCycleType;
}
这样,NoCycle -types 导致真正的循环类型,防止编译。
对于您的示例,NoCycle -structs 看起来像这样:
struct Foo_NoCycle {
    k: <u32 as NoCycleT>::NoCycleType, // == u32
    p: <Option<Rc<Bar>> as NoCycleT>::NoCycleType, // == Bar_NoCycle
}
struct Bar_NoCycle {
    s: <Option<Rc<Foo>> as NoCycleT>::NoCycleType, // == Foo_NoCycle
}
替换类型显示:
struct Foo_NoCycle {
    k: u32,
    p: Bar_NoCycle,
}
struct Bar_NoCycle {
    s: Foo_NoCycle,
}
这样,编译器看到 Foo_NoCycleBar_NoCycle形成无法编译的循环类型依赖。
这不是一个无需努力定义即可工作的解决方案 NoCycleT用于基本类型,并定义 NoCycleT对于诸如 Box 之类的事情, Rc , Arc , Vec , Mutex等。但是,我猜编译器会通知您缺少 impl s 以便您可以实现 NoCycleT对于实际需要的类型。

关于rust - 是否可以创建一个自定义派生来防止编译时类型之间的循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62972118/

相关文章:

rust - 使用尺寸大于屏幕的 newpad 时出现问题

rust - 我如何借用 RefCell<HashMap>、找到一个键并返回对结果的引用?

rust - 带有使用rust 的exec “tail -f xxx”

string - 从 Vec<char> 创建字符串

rust - 但没有借来的值(value)

hashmap - 恢复到 HashMap 中的先前值

rust - 如何在 .unzip() 返回的每个迭代器上使用 .collect()?

rust - 使用具有显式生命周期的特征时无法推断借用表达式的生命周期

rust - `cfg` 哪个总是真/假?

rust - 将闭包传递给特征方法 : expected type parameter, 找到闭包