假设我创建了以下记录:
type AnimalSound is (None, Woof);
type Animal is tagged
record
sound : AnimalSound := None;
end record;
然后我要从中导出另一条记录:
type Dog is new Animal with
record
nrPuppies : Integer := 0;
sound : AnimalSound := Woof;
end record;
编译器将给出一个名称冲突错误(与处的声明冲突),这听起来很合逻辑(您正在重新定义已经存在的内容),但是我想知道是否存在一种干净的方法来为字段中的字段设置不同的默认值Ada中的派生记录类型。也许有一个原因说明这种做法不好,并可能导致模棱两可或类似的问题?
答案 0 :(得分:2)
如果不提供AnimalSound,就无法实例化狗。
type AnimalSound is (None, Woof) with Default_Value => None; -- for Ada 2012 scalar types demonstration purpose
type Animal is tagged -- class
record
sound : AnimalSound; -- Defaults to None
end record;
type Dog is new Animal with record -- subclass
nrPuppies : Integer := 0;
end record;
Default_Dog : constant access Dog := new Dog'(sound => Woof,
nrPuppies => 0);
animal1 : access Animal := new Animal; -- sound defaults to None
animal2 : access Dog := new Dog'(sound => Woof, -- forced
nrPuppies => 2);
animal3 : access Dog := Default_Dog;
animal4 : access Dog := new Dog'(nrPuppies => 3); -- does not compile: no value supplied for component "sound"
因此,此构造表明,即使您为给定类强制使用默认值并在实例化时从中受益,也需要为任何子类赋予具有默认值的字段一个值。 (我没有检查,但我相信它也适用于访问字段。)
您还可以使用1个arg(nb的小狗)为Dog类定义一个构造函数。 该实现将为Sound设置一个值,但是概念仍然相同:
function fancy_default_constructor(nb_puppies : Integer) return not null access Dog is
begin
return new Dog'(sound => Woof, -- forced
nrPuppies => nb_puppies);
end fancy_default_constructor;
答案 1 :(得分:2)
如果使用合成而不是类型扩展名,则可以更改初始值。如果仍然需要动态调度(由Ada中的类型扩展提供),则可以模仿Rust的操作,并使用组合来表示实际的数据类型和提供调度的接口。
示例:
listen
如果您想进一步扩展扩展名(可以更改其他内部变量),则可以为Dog和Default_Dog添加另一个接口。
答案 2 :(得分:0)
我建议类似以下内容。
package Animals is
type Animal_Sound is (Default, None, Woof, Yelp, Howl, Meow, Oink);
type Animal is abstract tagged
record
Special_Sound: Animal_Sound := Default;
end record;
function Default_Sound (Creature: in Animal) return Animal_Sound is abstract;
function Sound (Creature: in Animal'Class) return Animal_Sound;
end;
package body Animals is
function Sound (Creature: in Animal'Class) return Animal_Sound is
begin
if Creature.Special_Sound /= Default then
return Creature.Special_Sound;
else
return Default_Sound (Creature);
end if;
end;
end Animals;
然后您可以按照以下方式添加一条狗。
with Animals; use Animals;
package Canine is
type Puppy_Count is range 0 .. 24;
type Dog is new Animal with
record
Litter_Size: Puppy_Count := 0;
end record;
overriding
function Default_Sound (Pooch: in Dog) return Animal_Sound is (Woof);
end;
这个想法是,某个类别的动物具有默认声音,但它可能具有特殊声音。我们具有Default
的特殊值Animal_Sound
,它表示动物的声音是其默认声音。我们定义了每个动物类别都必须覆盖的抽象函数Default_Sound
和便捷函数Sound
,该函数返回默认声音或适当的特殊声音。