数组作为结构体字段

38

我希望能在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
我听说如果它是唯一的,那么在编译时可以有一个大小未知的结构字段。我们如何做到这一点?

我原以为要求是“最后一个”,但无论如何这里也是一样的。我在 https://www.reddit.com/r/rust/comments/357ji5/using_structs_with_a_dst_array_member/ 找到了相关信息。 - Matthieu M.
在Rust中,数组具有编译时已知的固定大小。因此,您不需要一个“数组”。&[T]通常被称为切片,我不知道如何发音[T] - Shepmaster
@Shepmaster 我想那应该是“未定大小的数组”。 - Vladimir Matveev
2个回答

63
Rust没有变长(堆栈)数组的概念,你似乎在尝试使用它。Rust有几种不同的类似数组的类型:
- Vec(“向量”):动态大小;在堆上动态分配。这可能是你想要使用的。使用Vec::with_capacity(foo)进行初始化以避免过度分配(这将创建一个具有给定容量的空向量)。 - [T; n](“数组”):静态大小;存储在堆栈上。你需要在编译时知道大小,所以这对你来说行不通(除非我分析错误)。 - [T](“切片”):未定大小;通常从&[T]中使用。这是一种查看内存中连续一组T的视图。你可以通过引用数组或向量(称为“取一个数组/向量的切片”)甚至是从数组/向量的子集中获取它。由于未定大小,[T]不能直接用作变量(它可以用作未定大小结构体的成员),但你可以从指针后面查看它。指向[T]的指针是“fat”的;即它们有一个额外的字段表示长度。如果你想存储对现有数组的引用,则&[T]会很有用;但我认为这不是你想在这里做的事情。

谢谢您提到指向 [T] 的指针的“胖瘦”。我认为这是一条缺失的信息,因为我在其他地方都没有看到过。 - user19018

16
如果您事先不知道列表的大小,您有两个选择:
1. `&[T]` 只是对一些您不拥有的内存块的引用。 2. `Vec` 是您自己的存储。
正确的做法是使用 `Vec`。为什么?因为您希望子列表(`Rc` 数组)实际上归 `TreeNode` 所有。如果您使用 `&[T]`,这意味着其他人将保留该列表,而不是 `TreeNode`。通过某些生命周期技巧,您可以编写一些有效的代码,但是您必须远远超越编译器要求,因为借用的引用必须至少与 `TreeNode` 一样长。
最后,您问题中的一个句子表明存在误解:
“然而,该结构是不可变的,我不需要过度分配的 Vec。”
您混淆了可变性和所有权。当然,您可以拥有一个不可变的 Vec。看起来您想避免从堆中分配内存,但这是不可能的,因为您不知道子列表的大小。现在,如果您担心过度分配,可以使用 `with_capacity()` 和 `shrink_to_fit()` 等方法微调向量存储。
最后注意:如果您实际上知道列表的大小,因为它在编译时固定,那么您只需要使用 `[T; n]`,其中 `n` 是在编译时已知的。但这与 `[T]` 不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接