数组作为结构字段

Array as a struct field

我想在 Rust 中创建一个非二叉树结构。这是一个尝试

struct TreeNode<T> {
    tag : T,
    father : Weak<TreeNode<T>>,
    childrenlists : [Rc<TreeNode<T>>]
}

不幸的是,这无法编译。

main.rs:4:1: 8:2 error: the trait `core::marker::Sized` is not implemented for the type `[alloc::rc::Rc<TreeNode<T>>]` [E0277]
main.rs:4 struct TreeNode<T> {
main.rs:5     tag : T,
main.rs:6     father : Weak<TreeNode<T>>,
main.rs:7     childrenlist : [Rc<TreeNode<T>>]
main.rs:8 }
main.rs:4:1: 8:2 note: `[alloc::rc::Rc<TreeNode<T>>]` does not have a constant size known at compile-time
main.rs:4 struct TreeNode<T> {
main.rs:5     tag : T,
main.rs:6     father : Weak<TreeNode<T>>,
main.rs:7     childrenlist : [Rc<TreeNode<T>>]
main.rs:8 }
error: aborting due to previous error

如果我们用 Vec 替换数组,代码会编译。但是,该结构是不可变的,我不需要过度分配 Vec.

我听说有可能在编译时有一个大小未知的结构字段,前提是它是唯一的。我们该怎么做?

如果你事先不知道列表的大小,你有两个选择:

  1. &[T] 这只是对您不拥有的一些内存的引用
  2. Vec<T> 这是你自己的 存储空间。

这里正确的做法是使用 Vec。为什么?因为您希望子列表(Rc 的数组)实际上属于 TreeNode。如果您使用 &[T],则意味着其他人将保留列表,而不是 TreeNode。通过一些终生的技巧,您可以编写一些有效的代码,但您必须走很远才能取悦编译器,因为借用的引用必须至少与 TreeNode.

一样有效。

最后,你问题中的一句话说明了误解:

However, the structure is immutable and I do not need an overallocated Vec.

你混淆了可变性和所有权。当然你可以有一个不可变的 Vec。看起来您想避免从堆中分配内存,但这是不可能的,正是因为您不知道子列表的大小。现在,如果您担心过度分配,可以使用 with_capacity()shrink_to_fit().

等方法微调向量存储

最后一点:如果你真的知道列表的大小,因为它在编译时是固定的,你只需要使用 [T; n],其中 n 是编译时已知的。但这与 [T].

不同

Rust 没有可变长度(堆栈)数组的概念,您似乎想在这里使用它。

Rust 有几种不同的数组类型。

  • Vec<T> ("vector"):动态调整大小;在堆上动态分配。这就是您想要使用的可能。用 Vec::with_capacity(foo) 初始化它以避免过度分配(这会创建一个具有给定容量的空向量)。
  • [T; n] ("array"):静态大小;住在堆栈上。您需要在编译时知道大小,所以这对您不起作用(除非我错误地分析了您的情况)。
  • [T] ("slice"):未调整大小;通常从 &[T] 开始使用。这是对某处内存中一组连续的 T 的视图。您可以通过引用数组或向量(称为 "taking a slice of an array/vector"),甚至查看 array/vector 的子集来获取它。由于未调整大小,[T] 不能直接用作变量(它可以用作未调整大小的结构的成员),但您可以从指针后面查看它。指向 [T] 的指针是 fat ;即他们有一个额外的长度字段。如果您想存储对现有数组的引用,&[T] 会很有用;但我认为这不是您想在这里做的。