数组作为结构字段
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
.
我听说有可能在编译时有一个大小未知的结构字段,前提是它是唯一的。我们该怎么做?
如果你事先不知道列表的大小,你有两个选择:
&[T]
这只是对您不拥有的一些内存的引用
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]
会很有用;但我认为这不是您想在这里做的。
我想在 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
.
我听说有可能在编译时有一个大小未知的结构字段,前提是它是唯一的。我们该怎么做?
如果你事先不知道列表的大小,你有两个选择:
&[T]
这只是对您不拥有的一些内存的引用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]
会很有用;但我认为这不是您想在这里做的。