在不使用判别式的情况下在 Ada 中派生记录类型时分配值

Assign values when deriving a record type in Ada without using discriminants

我正在尝试在 Ada 中对三个实体建模:PersonWomanMan。我希望 Person 有一个字段 Gender,对于 Person 必须是 Unknown,对于 Man 和 [=20= 必须是 Male ] Woman.

我想将 ManWoman 实现为 Person 派生类型,其 Gender 字段分别为 MaleFemale

此外,我希望 Person's Gender 的唯一允许值是 Unknown,同样 Man 和 [=20] 的 Male =] 对于 Woman

我尝试了以下方法,但当然无法编译:

package Persons is

   type Genders is (Male, Female, Unknown);

   type Person is private;
   type Man is private;
   type Woman is private;

   function Get_Age    (Self : Person) return Integer;
   function Get_Name   (Self : Person) return String;
   function Get_Weight (Self : Person) return Float;
   function Get_Height (Self : Person) return Float;
   function Get_gender (Self : Person) return Genders;

private

   type Person is
      record
         Age            : Integer := 0;
         Name           : String (1..256) := (others => Character'Val(0)); -- '
         Height, Weight : Float := 0.0;
         Gender         : Genders := Unknown;
      end record;

   type Man   is new Person with Gender => Male;            
   type Woman is new Person with Gender => Female;

end Persons;

我不想将 Person 声明为参数类型,因为那样的话,Person 将被允许为 MaleFemaleUnknown,我不想允许这个。

是否可以做我想做的事?

Ada 2012 解决方案:

type Person is tagged record
   -- ...
   Gender : Genders := Unknown;
end record with Type_Invariant => (Person.Gender = Unknown);

type Man is new Person with null record
  with Type_Invariant => (Man.Gender = Male);
type Woman is new Person with null record
  with Type_Invariant => (Woman.Gender = Female);

我不确定这是否适用于非标记类型。

使用普通的 Ada 95(除了一些作弊以避免必须为包 ManWoman 提供主体):

private with Ada.Strings.Unbounded;

package Person is

   type Age_In_Years is range 0 .. 200;
   type Weight_In_kg is delta 0.1 range 0.0 .. 300.0;
   type Height_In_m  is delta 0.01 range 0.0 .. 3.0;
   type Genders      is (Male, Female);

   type Instance is abstract tagged private;
   subtype Class is Instance'Class; -- '

   function Age    (Self : in Instance) return Age_In_Years;
   function Name   (Self : in Instance) return String;
   function Weight (Self : in Instance) return Weight_In_kg;
   function Height (Self : in Instance) return Height_In_m;
   function Gender (Self : in Instance) return Genders is abstract;

private

   type Instance is abstract tagged
      record
         Age    : Age_In_Years;
         Name   : Ada.Strings.Unbounded.Unbounded_String;
         Weight : Weight_In_kg;
         Height : Height_In_m;
      end record;

end Person;
with Person;

package Man is

   subtype Parent is Person.Instance;
   type Instance is new Parent with null record;
   subtype Class is Instance'Class; -- '

   overriding
   function Gender (Self : in Instance) return Person.Genders is (Person.Male);

end Man;
with Person;

package Woman is

   subtype Parent is Person.Instance;
   type Instance is new Parent with null record;
   subtype Class is Instance'Class; -- '

   overriding
   function Gender (Self : in Instance) return Person.Genders is (Person.Female);

end Woman;

我知道你说没有判别式,但你给出的理由是为了防止它们之间的赋值。您愿意考虑将判别式隐藏在私有类型后面吗?这将防止客户端代码进行赋值,如果您使用类型派生,它将防止您在包的内部代码中意外地分配它们。下面是两个不同的示例,您可以在其中隐藏判别式,从而防止赋值。编辑:添加了使用泛型的第三个选项。

procedure jdoodle is

    package Persons1 is

       type Genders is (Male, Female, Unknown);

       type Person is private;
       type Man is private;
       type Woman is private;

    private

       type Implementation(Gender : Genders) is
          record
             Age            : Integer := 0;
             Name           : String (1..256) := (others => Character'Val(0)); -- '
             Height, Weight : Float := 0.0;
          end record;

       type Person is new Implementation(Unknown);
       type Man    is new Implementation(Male);         
       type Woman  is new Implementation(Female);

    end Persons1;

    package Persons2 is

       type Genders is (Male, Female, Unknown);

       type Person is private;
       type Man is private;
       type Woman is private;

    private

       type Person(Gender : Genders := Unknown) is
          record
             Age            : Integer := 0;
             Name           : String (1..256) := (others => Character'Val(0)); -- '
             Height, Weight : Float := 0.0;
          end record;

       type Man    is new Person(Male);         
       type Woman  is new Person(Female);

    end Persons2;

    package Persons3 is

       type Genders is (Male, Female, Unknown);

       type Person is private;
       type Man is private;
       type Woman is private;

    private

       generic
           The_Gender : Genders := Unknown;
       package Generic_Persons is
           type Person is record
               Age            : Integer := 0;
               Name           : String (1..256) := (others => Character'Val(0)); -- '
               Height, Weight : Float := 0.0;
               Gender         : Genders := The_Gender;
           end record;
       end Generic_Persons;

       package Person_Pkg is new Generic_Persons(Unknown);
       package Man_Pkg is new Generic_Persons(Male);
       package Woman_Pkg is new Generic_Persons(Female);

       type Person is new Person_Pkg.Person;
       type Man    is new Man_Pkg.Person;         
       type Woman  is new Woman_Pkg.Person;

    end Persons3;

begin
    null;
end jdoodle;