在Ada中将字符串作为任务创建鉴别器传递

在Ada中将字符串作为任务创建鉴别器传递,ada,Ada,我正在用Ada迈出我的第一步,我发现我很难理解如何在其他语言中立即执行常见的、甚至平庸的操作 在本例中,我定义了以下任务类型(和访问类型,以便创建新实例): 正如您所看到的,这是一个简单的任务,在创建实例时可以向其传递3个判别式字符串\u Ref定义为: type String_Ref is access all String; 我之所以使用它,是因为显然你不能使用“普通”类型作为任务的区别,只能使用引用或原语类型 所以我想创建这样一个任务的实例,但是无论我做什么,我都会得到一个错误。我

我正在用Ada迈出我的第一步,我发现我很难理解如何在其他语言中立即执行常见的、甚至平庸的操作

在本例中,我定义了以下任务类型(和访问类型,以便创建新实例):

正如您所看到的,这是一个简单的任务,在创建实例时可以向其传递3个判别式<代码>字符串\u Ref定义为:

   type String_Ref is access all String;
我之所以使用它,是因为显然你不能使用“普通”类型作为任务的区别,只能使用引用或原语类型

所以我想创建这样一个任务的实例,但是无论我做什么,我都会得到一个错误。我无法通过简单的操作直接传递字符串:

  Passenger1 := new Passenger(Name => "foo", Workplace_Station => "man", Home_Station => "bar");
因为这些是字符串,而不是字符串的引用,这很公平。 所以我试着:

task body Some_Task_That_Tries_To_Use_Passenger is
          Passenger1 : Passenger_Ref;
          Name1 : aliased String := "Foo";
          Home1 : aliased String := "Man";
          Work1 : aliased String := "Bar";

    begin

          Passenger1 := new Passenger(Name => Name1'Access, Workplace_Station => Work1'Access, Home_Station => Home1'Access);
但这也不起作用,因为据我所知,
Home1
/
Name1
/
Work1
变量是task
一些试图使用乘客的任务的局部变量,因此乘客的“构造器”无法使用


老实说,我不明白我该怎么做。我过去使用过几种编程语言,但我从未遇到过这么多麻烦,将一个简单的字符串传递给构造函数,我觉得自己像个十足的白痴,但我不明白为什么这样一个常见的操作会如此复杂,我确信我对这个问题的理解是错误的,请告诉我正确的方法,因为我快发疯了:是的,我同意这是一个严重的语言问题,任务和记录类型的区分必须是离散的。幸运的是,对于任务类型有一个简单的解决方案——数据可以通过“入口”点传递


Ada实际上没有构造函数。在其他语言中,构造函数本质上是一种接受参数的方法,并有一个处理这些参数的主体。试图让鉴别器充当构造函数是行不通的,因为并没有子程序体来处理鉴别器。可能看起来应该是这样,因为语法包含一个类型,后跟一个括号中的判别值列表,并用逗号分隔。但这只是表面上的相似。判别式的目的不是模拟构造函数

对于“普通”记录类型,构造函数的最佳替代品是返回该类型对象的函数。(这类似于在Java等语言中使用静态“工厂方法”而不是构造函数。)函数可以接受
String
参数或任何其他类型的参数

对于任务类型来说,这有点棘手,但您可以编写一个函数来返回对任务的访问权

type Passenger_Acc is access all Passenger;
function Make_Passenger (Name : String;
                         Workplace_Station : String;
                         Home_Station : String) return Passenger_Acc;
要实现它,您需要在
乘客
任务中定义一个条目(参见Roger Wilco的回答),然后您可以在正文中使用它:

function Make_Passenger (Name : String;
                         Workplace_Station : String;
                         Home_Station : String) return Passenger_Acc is
    Result : Passenger_Acc;
begin
    Result := new Passenger;
    Result.Construct (Name, Workplace_Station, Home_Station);
    return Result;
end Make_Passenger;

(您必须通过返回任务访问权限来实现这一点。我认为您无法让函数返回任务本身,因为您必须使用扩展的返回来设置任务对象,并且任务对象在函数返回后才被激活,因此无法接受条目。)

它不必那么复杂。您可以使用匿名访问类型并按需分配字符串,但是请考虑如果您真的希望字符串是判别式的。 下面是一个完整的工作示例:

with Ada.Text_IO;

procedure String_Discriminants is
   task type Demo (Name : not null access String);

   task body Demo is
   begin
      Ada.Text_IO.Put_Line ("Demo task named """ & Name.all & """.");
   exception
      when others =>
         Ada.Text_IO.Put_Line ("Demo task terminated by an exception.");
   end Demo;

   Run_Demo    : Demo (new String'("example 1"));
   Second_Demo : Demo (new String'("example 2"));
begin
   null;
end String_Discriminants;

另一个选项是在库级包中声明字符串为别名常量,但是您非常接近枚举判别式,并且在丢弃它之前应该仔细考虑该选项。

< P>我认为另一种解决方案是:

task body Some_Task_That_Tries_To_Use_Passenger is
      Name1      : aliased String := "Foo";
      Home1      : aliased String := "Man";
      Work1      : aliased String := "Bar";
      Passenger1 : aliased Passenger(
                         Name              => Name1'Access,
                         Workplace_Station => Work1'Access,
                         Home_Station      => Home1'Access
                       );

begin
 --...
你说

“老实说,我不明白我该怎么做。我过去使用过几种编程语言,但我从未遇到过这么多麻烦,将一个简单的字符串传递给构造函数,我觉得自己像个十足的白痴,但我不明白为什么这样一个常见的操作会如此复杂,我确信我对这个问题的理解是错误的,请告诉我正确的方法,因为我快发疯了:D“

Ada的访问类型常常令人困惑。主要问题是Ada没有自动垃圾收集功能,并且希望确保您不会遇到返回局部变量指针的问题。这两种类型的组合会产生一组奇怪的规则,迫使您仔细设计解决方案


如果您确信自己的代码是好的,那么您可以始终对别名字符串使用“无限制”访问。这让您有责任确保访问的变量不会从任务下面消失。

您说使用Discrimites作为构造函数不太好。但是,有什么技术原因不允许这样做吗?除了歧视之外,还有没有其他方法在不使用指针或无界字符串的情况下传递有界字符串?@RogerWilco Discriminants的目的是参数化类型,而不是将值传递给类型。我很难解释这种区别,但它确实存在。将值传递给构造函数(在其他语言中)更类似于指定记录字段的初始值。我们在Ada中不使用鉴别器。这不是它们的目的。回答这样的问题真的没有多大意义,比如“有什么技术原因不能将特性a扭曲成完全不同的特性B吗?”?“我明白了。您可以将一个数字传递给一个记录,该记录可以作为范围的一部分来定义某个有界类型的长度,例如类型a(N:Integer)是记录名:String(1..N)。。。结束记录;这是正确的Ada,但实际上不允许传入有界类型。我认为这是有用的,因为在记录中创建字符串组件需要计算组件所需的字符数(例如“名称”),然后使用适当的le赋值
with Ada.Text_IO;

procedure String_Discriminants is
   task type Demo (Name : not null access String);

   task body Demo is
   begin
      Ada.Text_IO.Put_Line ("Demo task named """ & Name.all & """.");
   exception
      when others =>
         Ada.Text_IO.Put_Line ("Demo task terminated by an exception.");
   end Demo;

   Run_Demo    : Demo (new String'("example 1"));
   Second_Demo : Demo (new String'("example 2"));
begin
   null;
end String_Discriminants;
task body Some_Task_That_Tries_To_Use_Passenger is
      Name1      : aliased String := "Foo";
      Home1      : aliased String := "Man";
      Work1      : aliased String := "Bar";
      Passenger1 : aliased Passenger(
                         Name              => Name1'Access,
                         Workplace_Station => Work1'Access,
                         Home_Station      => Home1'Access
                       );

begin
 --...