2015-05-15 5 views
7

Я хотел бы создать не двоичную древовидную структуру в Rust. ПопробуйтеArray as a struct field

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.

Я слышал, что может быть возможно иметь поле структуры с неизвестным размером во время компиляции при условии, что оно уникально. Как мы можем сделать это?

+0

Я думал, что это требование было «последним», но в любом случае это также имеет место здесь. Я нашел https://www.reddit.com/r/rust/comments/357ji5/using_structs_with_a_dst_array_member/ –

+0

В Rust * массивы * имеют фиксированный размер, известный во время компиляции. Таким образом, вам не нужен «массив». '& [T]' обычно называется * срезом *, я не знаю, как произносится «[T]». – Shepmaster

+0

@Shepmaster Я предполагаю, что это будет «unsized array». –

ответ

12

Ржавчина не имеет понятия массива переменной длины (стека), который вы, кажется, пытаетесь использовать здесь.

Rust имеет пару различных типов массива.

  • Vec<T> ("vector"): Dynamicically size; динамически распределенных по куче. Это Возможно, Что вы хотите использовать. Инициализируйте его Vec::with_capacity(foo), чтобы избежать обсчета (это создает пустой вектор с заданной емкостью).
  • [T; n] ("массив"): размер статического размера; живет в стеке.Вы должны знать размер во время компиляции, так что это не сработает для вас (если я не разобрал вашу ситуацию).
  • [T] ("slice"): не определено; обычно используется от &[T]. Это вид в смежном наборе T s в памяти где-то. Вы можете получить его, взяв ссылку на массив или вектор (называемый «взятием среза массива/вектора») или даже выбрав представление в подмножество массива/вектора. Будучи небезопасным, [T] не может использоваться непосредственно как переменная (его можно использовать как член unsized struct), но вы можете просмотреть его из-за указателя. Указателями, указывающими [T], являются fat; то есть они имеют дополнительное поле для длины. &[T] было бы полезно, если вы хотите сохранить ссылку на существующий массив; но я не думаю, что это то, что вы хотите сделать здесь.
+0

Спасибо, что упомянул жирность указателя на '[T]'. Я думаю, что это недостающая часть информации, поскольку я ее больше нигде не видел. – user19018

4

Если вы не знаете размер списка заранее, у вас есть два варианта:

  1. &[T] который просто ссылка на какой-то части памяти, что вы не владеете
  2. Vec<T> который является ваш собственный хранения.

Правильная вещь здесь - использовать Vec. Зачем? Поскольку вы хотите, чтобы список детей (массив Rc) фактически принадлежал TreeNode. Если вы использовали &[T], это означает, что кто-то еще сохранит список, а не TreeNode. С некоторой пожизненной обманкой вы могли бы написать какой-то действительный код, но вам нужно было бы пойти очень далеко, чтобы угодить компилятору, потому что заимствованная ссылка должна быть действительна, по крайней мере, до TreeNode.

Наконец, предложение в вашем вопросе показывает непонимание:

Однако структура не является неизменной, и я не нужен overallocated VEC.

Вы путаете изменчивость и владение. Уверен, у вас может быть непреложный Vec. Похоже, вы хотите избежать выделения памяти из кучи, но это невозможно, именно потому, что вы не знаете размер списка детей. Теперь, если вы заинтересованы в обводнении, вы можете точно настроить векторное хранилище с помощью методов, таких как with_capacity() и shrink_to_fit().

Последнее примечание: если вы действительно знаете размер списка, потому что он фиксируется во время компиляции, вам просто нужно использовать [T; n], где n известен во время компиляции. Но это не то же самое, что [T].