(Ada 2012)编译时错误“预期的私有类型...发现了复合类型”

时间:2019-08-21 14:14:06

标签: ada

我正在尝试在Ada 2012中编写一个非常原始的链表示例程序。我的代码包含3个文件,linked_list.adblinked_list.ads和{{1} }。

用户将运行该程序,只需输入数字序列,然后输入零以结束该序列并退出。该程序只是从标准输入中读取这些数字,将列表打印出来然后退出。

这是我的完整代码...

文件:“ main.adb”

main.adb

文件:“ linked_list.ads”

with Linked_List; use Linked_List;

procedure Main is
  L : access List_Item;
begin
  L := new List_Item'(null, 0);

  while Append_Item (L) loop
    null;
  end loop;

  Print_List (L);
end Main;

文件:“ linked_list.ads”

with Ada.Text_IO; use Ada.Text_IO;

package Linked_List is
  type List_Item is private;

  function Append_Item (List_Head : access List_Item) return Boolean;
  procedure Print_List (List_Head : access List_Item);

private

  type List_Item is
    record
      Next_Item : access List_Item;
      ID : Integer;
    end record;

end Linked_List;

我正在使用Gnatmake 7.4.0,而我的编译器命令行是

with Ada.Text_IO; use Ada.Text_IO;

package body Linked_List is

  function Append_Item (List_Head : access List_Item) return Boolean is
    Runner : access List_Item := List_Head;
    new_ID : Integer;
  begin
    if Runner.Next_Item = null then -- if we've found the last item
      Put ("Enter ID for new Item (enter 0 to stop): ");
      Get (new_ID);

      if new_ID = 0 then
        return false; -- user wants to quit
      else if;
        -- add a new item to the end of the list
        Runner.Next_Item := new List_Item'(null, new_ID);
        return true;
      end if;
    else;
      Runner := Runner.Next_Item;
    end if;
  end Append_Item;

  procedure Print_List (List_Head : access List_Item);
    Runner : access List_Item := List_Head;
  begin
    if Runner = null then
      return;
    else;
      Put ("Item ID: "); Put (Runner.ID);
      Runner := Runner.Next_Item;
    end if;
  end Print_List;

end Linked_List;

我看到的错误消息是:

gnatmake -gnaty -gnaty2 -gnat12 main.adb

我写的语法似乎与我试图从那本书中读到的一致:约翰·巴恩斯(John Barnes)的“ Program in in Ada 2012”。

该记录是私有声明的,因此我的客户端程序(主程序)看不到列表机制内部工作的细节。我在做什么错了?

2 个答案:

答案 0 :(得分:3)

原因是:type List_Item is private(来自Ada代码的纯英文)!

这意味着Linked_List程序包的作者不希望其用户使用其详细信息(这是一个包含两个部分的记录)。在更复杂的软件中,隐藏这些详细信息很有用,因为这些详细信息可能会更改,并且如果用户使用明细(在这种情况下为复合类型)会在List_Item类型的设计更改后变得不兼容的细节而陷入麻烦。 有两种解决方案:

  1. 将List_Item设为公开(如果您要构建“真实”软件,通常是一个不好的解决方案)
  2. 在专用部分的Null_List : constant List_Item;type List_Item is private之后添加Null_List : constant List_Item := (null, 0);。然后,您可以在main.adb中使用Null_List

答案 1 :(得分:1)

实际上,类型是私有的,这意味着客户端“ main.adb”不能像在“ new”调用中那样对其内部进行假设,并且Zerte的两种解决方案都可以解决该问题(并且我同意:首先不是解决方案!)

第三个解决方案:“对象工厂”设计模式。

package Linked_List is
  type List_Item is private;

  function Create_Item(ID_Value : Natural) return List_Item;

功能主体应该很明显。请注意,对于更复杂的示例,尤其是对于limited private类型,可能需要Ada-2005的“扩展返回”语法。

可以用不同类型项的变体重载此构造函数(实际上是对象工厂的示例),并提供Zerte的Null_List : constant List_Item;作为替代。

客户端可以将此功能用作

L := Create_Item(0);