Inheritance 一个结构是否可以扩展现有结构,保留所有字段?
使用Inheritance 一个结构是否可以扩展现有结构,保留所有字段?,inheritance,struct,rust,Inheritance,Struct,Rust,使用rust 1.2.0 问题 我仍在学习Rust(来自Javascript背景)的过程中,我正在试图弄清楚一个structStructB是否可以扩展现有的structStructA,以便StructB拥有StructA上定义的所有字段 在Javascript(ES6语法)中,我基本上可以这样做 class Person { constructor (gender, age) { this.gender = gender; this.age = age;
rust 1.2.0
问题
我仍在学习Rust(来自Javascript背景)的过程中,我正在试图弄清楚一个structStructB
是否可以扩展现有的structStructA
,以便StructB
拥有StructA
上定义的所有字段
在Javascript(ES6语法)中,我基本上可以这样做
class Person {
constructor (gender, age) {
this.gender = gender;
this.age = age;
}
}
class Child extends Person {
constructor (name, gender, age) {
super(gender, age);
this.name = name;
}
}
约束
来自我无法控制的外部StructA
包裹cargo
错误:虚拟结构已从语言中删除
。后来我搜索了一下,发现它已经很快被发现了
我也发现了这一点,但由于StructA是一个外部货物包装,我认为我不可能把它变成一个特征
那么,在Rust中实现这一点的正确方法是什么呢?Rust没有任何类型的结构继承。如果希望
StructB
包含与StructA
相同的字段,则需要使用组合
struct StructB {
a: StructA,
// other fields...
}
此外,为了澄清,特征只能定义方法和相关类型;它们不能定义字段
如果您想将StructB
用作StructA
,可以通过实现and traits来实现,这将允许编译器隐式地将指向StructB
s的指针转换为指向StructA
s的指针:
struct StructA;
impl StructA {
fn name(&self) -> &'static str {
"Anna"
}
}
struct StructB {
a: StructA,
// other fields...
}
impl std::ops::Deref for StructB {
type Target = StructA;
fn deref(&self) -> &Self::Target {
&self.a
}
}
fn main() {
let b = StructB { a: StructA };
println!("{}", b.name());
}
没有任何东西与此完全相符。我想到了两个概念
struct Person {
age: u8,
}
struct Child {
person: Person,
has_toy: bool,
}
impl Person {
fn new(age: u8) -> Self {
Person { age: age }
}
fn age(&self) -> u8 {
self.age
}
}
impl Child {
fn new(age: u8, has_toy: bool) -> Self {
Child { person: Person::new(age), has_toy: has_toy }
}
fn age(&self) -> u8 {
self.person.age()
}
}
fn main() {
let p = Person::new(42);
let c = Child::new(7, true);
println!("I am {}", p.age());
println!("My child is {}", c.age());
}
您可以简单地将一个结构嵌入到另一个结构中。内存布局美观紧凑,但您必须手动将所有方法从Person
委派给Child
或借出&Person
trait SayHi {
fn say_hi(&self);
}
struct Person {
age: u8,
}
struct Child {
age: u8,
has_toy: bool,
}
impl SayHi for Person {
fn say_hi(&self) {
println!("Greetings. I am {}", self.age)
}
}
impl SayHi for Child {
fn say_hi(&self) {
if self.has_toy {
println!("I'm only {}, but I have a toy!", self.age)
} else {
println!("I'm only {}, and I don't even have a toy!", self.age)
}
}
}
fn greet<T>(thing: T)
where T: SayHi
{
thing.say_hi()
}
fn main() {
let p = Person { age: 42 };
let c = Child { age: 7, has_toy: true };
greet(p);
greet(c);
}
trait SayHi{
fn say__hi(&self);
}
结构人{
年龄:u8,
}
结构子对象{
年龄:u8,
玩具:布尔,
}
为个人祈祷{
fn say_hi(&self){
println!(“你好,我是{}”,self.age)
}
}
为孩子祈祷{
fn say_hi(&self){
如果赛尔夫有玩具{
println!(“我只是{},但我有一个玩具!”,self.age)
}否则{
println!(“我只是{},甚至没有玩具!”,self.age)
}
}
}
fn问候(事物:T)
T:SayHi在哪里
{
说你好
}
fn main(){
设p=人{年龄:42};
设c=Child{age:7,has_toy:true};
问候(p);
问候(c);
}
您可以选择实现
Deref
或DerefMut
。然而,我不同意以这种方式使用这些特性。我的观点类似于这样一种观点,即仅仅为了代码重用而使用经典的面向对象继承是错误的。“偏好组合而非继承”=>“偏好组合而非继承”。然而,我确实希望有一种语言特性,它能够实现简洁的委托,减少写作的麻烦。另一种选择是使用泛型:
struct StructB {
a: StructA,
// other fields...
}
trait IAnimalData{}
结构动物{
名称:String,
年龄:164岁,
儿童资料:D,
}
结构狗{
最喜欢的玩具:绳子,
}
狗{}的impl IAnimalData
然后你可以实现这样的“child”方法,它只适用于狗:
impl动物{
pub fn bark(和self)->字符串{
将“树皮!”返回给_owned();
}
}
如果您希望父方法适用于所有动物,您可以这样实现它们:
//为所有动物实现“呼吸”方法
植入动物{
fn呼吸(){}
}
好的方面是,你不必经历将
Dog
中的方法转发到Animal
中的方法的痛苦;您可以直接在impl Animal
中使用它们。此外,您还可以通过Animal
的任何方法访问Animal
中定义的任何字段。糟糕的是,您的继承链总是可见的(也就是说,您可能永远不会在代码中使用Dog
,而是使用Animal
)。此外,如果继承链很长,您可能会得到一些非常愚蠢、冗长的类型,如Animal
。我想在这一点上,最好使用类型别名。这正是我所怀疑的。感谢您的确认和快速回答!对于其他的人来说。。。这些代码片段是否为您编译?如果我没有new
的返回类型,我会得到一个编译错误。@drebabels没有,这是我在传输时的错误。我确保它现在可以编译:-)@Shepmaster:为Child
实现Deref
和DerefMut
将大大有助于使组合方法很好地工作。因为在大多数情况下,你可以把一个孩子
当作一个人
@chrismorge来对待,这可能是真的,但我属于那些认为这在语义上不正确的人。总有一天,我会写下我的RFC,提出一个替代方案。。。总有一天……这方面有什么消息吗?我认为在不知道您想要使用新生成的结构的上下文和原因的情况下回答这个问题总是次优的。在我看来,这些设计决策在很大程度上取决于特定的用例。这是一个很好的解决方案,但其他Rust程序员可能会嘲笑你命名traitsITraitName
。只要TraitName
就可以了。trait和类型不是同一名称空间的一部分,因此很少有任何混淆(至少,只要您对trait对象类型使用dyn
。@trentcl“嘲笑您”是