Rust 中自引用结构的替代方案?



这里有很多关于 Rust 中自引用结构的问题,我想我已经全部阅读了,但我仍然无法理解这些东西。在 Rust 中处理自引用结构存在什么样的设计模式?我会列出我的想法,以便其他人可以告诉我哪里出错了(我有一种感觉,这是在开始(。

当我学习一门新语言时,我尝试实现相同的游戏,对于 Rust,我遇到了这个问题:我们有资源,其中一些可以从其他资源中获取。(假设它们形成一个 DAG。

我天真的建模尝试是这样的:

struct Resource {
name: String,
production_cost: HashMap<&Resource, i32>,
// other data
}

我们需要一个生命周期注释作为参考,因此它变得Resource<'a>带有HashMap<&'a Resource, i32>.

这种形式的Vec<Resource>是不切实际的(不可能?(,所以另一种尝试是提升一个级别:

struct Resource {
name: String,
// other data
}
struct ResourceConfig {
resources: Vec<Resource>,
resource_costs: HashMap<&Resource, HashMap<&Resource, i32>>,
}

我也想不出构建其中之一的方法。我能想到的接下来两个选项是:

  1. 将所有内容包装在 RefCell/Rc(或 Arc/Mutexes(中。这似乎需要太多的键入,更不用说引用计数性能开销了(我确信这在我的情况下是微不足道的(。
  2. 将索引传递到主向量。

所以最终结果 (2( 如下所示:

type RIndex = usize;
type ResourceSet = HashMap<RIndex, i32>;
struct Resource {
name: String,
// other data
}
struct ResourceConfig {
resources: Vec<Resource>,
resource_costs: HashMap<RIndex, ResourceSet>,
}

其余代码只是传递一堆RIndex(并保留一个&ResourceConfig引用来进行转换(。我可以以击键为代价将RIndex从类型别名升级到新类型以确保类型安全(可能值得吗?(,但最终我觉得我只是在做自己的指针管理 - 而不是担心无效/空指针,我担心RIndex超出范围。

我在这里错过了什么?(不安全的代码?

在C++中,我会做这样的事情:

class Resource {
std::string name;
std::unordered_map<Resource*, int> production_cost;
// Probably wrap the unordered_map in its own class, maybe with a Resource reference, etc.
}

(当然,我会失去终身保证,但资源都将存在于某个地方的同一对象中,因此进行工作并不难。

将索引传递到主向量。

您正在描述一个竞技场 – 可以通过索引相互链接的结构向量。有一些不错的板条箱可以让你做到这一点,并提供一些编译时检查。

在您的情况下,我们可以更进一步 - 因为您不需要在创建资源类型后销毁它,因此所有资源都可以在相同的生存期内(一旦创建(。因此,理论上您应该能够让竞技场中的物品相互引用。类型竞技场可以让你做到这一点!

use typed_arena::Arena;
fn main() {
let resources = Arena::<Resource>::default();
let iron = resources.alloc(Resource {
name: "iron".to_string(),
cost: vec![],
});
let water = resources.alloc(Resource {
name: "water".to_string(),
cost: vec![],
});
let rust = resources.alloc(Resource {
name: "rust".to_string(),
cost: vec![iron, water],
});
println!("{iron:?}");
println!("{water:?}");
println!("{rust:?}");
}
#[derive(Debug)]
struct Resource<'a> {
name: String,
cost: Vec<&'a Resource<'a>>,
}
Resource { name: "iron", cost: [] }
Resource { name: "water", cost: [] }
Resource { name: "rust", cost: [Resource { name: "iron", cost: [] }, Resource { name: "water", cost: [] }] }

最新更新