我正在学习Rust,来自几乎完全垃圾收集的背景。因此,我想确保在编写第一个程序时我正站起来。
Rust网站上的教程说我应该怀疑使用不是&
的指针。考虑到这一点,这就是我在我的小班级层次结构中所得到的(名称改为保护无辜)。要点是,我有两个不同的实体,让我们说Derived1
和Derived2
,它们共享一些行为和结构。我将公共数据放入Foo
结构并将常见行为转换为Fooish
特征:
struct Foo<'a> {
name: &'a str,
an_array: &'a [AnEnumType],
/* etc. */
}
struct Derived1<'a> {
foo: &'a Foo<'a>,
other_stuff: &'a str,
}
struct Derived2<'a> {
foo: &'a Foo<'a>,
/* etc. */
}
trait Fooish<'a> {
fn new(foo: &'a Foo<'a>) -> Self;
/* etc. */
}
impl<'a> Fooish<'a> for Derived1<'a> {
fn new(foo: &'a Foo<'a>) -> Derived1<'a> {
Derived1 { foo: foo, other_stuff: "bar" }
}
/* etc. */
}
/* and so forth for Derived2 */
我的问题:
&
指针作为结构字段是否正确? (例如对于字符串数据,以及其大小因实例而异的数组字段?Foo
中的Derived
怎么办?)谢谢!
答案 0 :(得分:2)
我会说这根本不是惯用语,但有时 任务需要逐步摆脱惯用法,目前尚不清楚这是否真的是这种情况。
我建议你不要使用在类和继承方面运行的OO语言的想法 - 它们在Rust中无法正常工作。相反,您应该根据所有权来考虑您的数据:如果给定的结构拥有数据,请问自己一个问题?换句话说,数据是自然属于结构还是可以在某处独立使用?
如果您将此推理应用于您的结构:
struct Foo<'a> {
name: &'a str,
an_array: &'a [AnEnumType],
/* etc. */
}
struct Derived1<'a> {
foo: &'a Foo<'a>,
other_stuff: &'a str,
}
struct Derived2<'a> {
foo: &'a Foo<'a>,
/* etc. */
}
你会发现使用引用编码继承是没有意义的。如果Derived1
引用了Foo
,那么暗示这个Foo
是在其他地方创建的,Derived1
只是借用了一段时间。虽然这个可能是你真正想要的东西,但这并不是继承的工作原理:继承的结构/类通常包含其中的“父”内容;换句话说,他们拥有他们的父数据,所以这将是更合适的结构:
struct Foo<'a> {
name: &'a str,
an_array: &'a [AnEnumType],
/* etc. */
}
struct Derived1<'a> {
foo: Foo<'a>
other_stuff: &'a str,
}
struct Derived2<'a> {
foo: Foo<'a>,
/* etc. */
}
请注意,Derived*
结构现在包含Foo
。
对于字符串和数组(实际上是字符串切片和数组切片),是的,如果要将它们保存在结构中,则必须使用生命周期注释。但是,通常不会发生这种情况,而且,基于所有权设计结构通常有助于确定这应该是切片还是动态分配的String
或Vec
。有一个nice tutorial on strings,当你需要使用自有字符串和需要切片时,它解释了其他所有内容。相同的推理适用于&[T]
/ Vec<T>
。简而言之,如果您的struct 拥有字符串/数组,则必须使用String
/ Vec
。否则,请考虑使用切片。