(Ada 2012) 编译时错误 "expected private type... found composite type"
(Ada 2012) compile-time error "expected private type... found composite type"
我正在尝试在 Ada 2012 中编写一个非常原始的链表示例程序。我的代码包含 3 个文件,linked_list.adb
,linked_list.ads
和 main.adb
.
用户将 运行 程序并简单地输入一个数字序列,然后输入零以结束序列并退出。该程序只是从 std-in 中读取这些数字,打印出列表,然后退出。
这是我的完整代码...
文件:"main.adb"
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;
文件:"linked_list.ads"
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 7.4.0,我的编译器命令行是
gnatmake -gnaty -gnaty2 -gnat12 main.adb
我看到的错误消息是:
gnatmake -gnaty -gnaty2 -gnat12 main.adb
aarch64-linux-gnu-gcc-7 -c -gnaty -gnaty2 -gnat12 main.adb
main.adb:6:22: expected private type "List_Item" defined at linked_list.ads:4
main.adb:6:22: found a composite type
gnatmake: "main.adb" compilation error
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 4
我写的语法似乎与我试图从中学习的书一致:"Programming in Ada 2012" 约翰·巴恩斯。
该记录是私下声明的,因此我的客户端程序(主程序)看不到列表机制内部工作的详细信息。我做错了什么?
原因是:type List_Item is private
(来自 Ada 代码的简单英语)!
这意味着包 Linked_List 的作者不希望其用户使用其详细信息(这是一个包含两个组件的记录)。在更复杂的软件中,隐藏这些细节很有用,因为它们可能会发生变化,如果用户使用在设计更改后变得不兼容的细节(在本例中为复合类型),用户会 运行 陷入麻烦在类型 List_Item 中。
有两种解决方案:
- 制作 List_Item public(如果您想构建 "real" 软件,通常是一个糟糕的解决方案)
- 私密部分在
type List_Item is private
和Null_List : constant List_Item := (null, 0);
后加上Null_List : constant List_Item;
。然后你可以在 main.adb. 中使用 Null_List
确实类型是私有的,这意味着客户端 "main.adb" 不能像在 "new" 调用中那样对其内部进行假设,Zerte 的两种解决方案都解决了这个问题(并且我同意:第一个不是解决方案!)
第三种解决方案:"object factory" 设计模式。
package Linked_List is
type List_Item is private;
function Create_Item(ID_Value : Natural) return List_Item;
函数体应该是显而易见的。请注意,对于更复杂的示例,尤其是 limited private
类型,可能需要 Ada-2005 的 "extended return" 语法。
可以使用不同类型的项目的变体重载此构造函数(实际上是对象工厂的示例),并提供 Zerte 的 Null_List : constant List_Item;
作为替代。
客户端可以使用此功能
L := Create_Item(0);
我正在尝试在 Ada 2012 中编写一个非常原始的链表示例程序。我的代码包含 3 个文件,linked_list.adb
,linked_list.ads
和 main.adb
.
用户将 运行 程序并简单地输入一个数字序列,然后输入零以结束序列并退出。该程序只是从 std-in 中读取这些数字,打印出列表,然后退出。
这是我的完整代码...
文件:"main.adb"
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;
文件:"linked_list.ads"
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 7.4.0,我的编译器命令行是
gnatmake -gnaty -gnaty2 -gnat12 main.adb
我看到的错误消息是:
gnatmake -gnaty -gnaty2 -gnat12 main.adb
aarch64-linux-gnu-gcc-7 -c -gnaty -gnaty2 -gnat12 main.adb
main.adb:6:22: expected private type "List_Item" defined at linked_list.ads:4
main.adb:6:22: found a composite type
gnatmake: "main.adb" compilation error
Makefile:2: recipe for target 'all' failed
make: *** [all] Error 4
我写的语法似乎与我试图从中学习的书一致:"Programming in Ada 2012" 约翰·巴恩斯。
该记录是私下声明的,因此我的客户端程序(主程序)看不到列表机制内部工作的详细信息。我做错了什么?
原因是:type List_Item is private
(来自 Ada 代码的简单英语)!
这意味着包 Linked_List 的作者不希望其用户使用其详细信息(这是一个包含两个组件的记录)。在更复杂的软件中,隐藏这些细节很有用,因为它们可能会发生变化,如果用户使用在设计更改后变得不兼容的细节(在本例中为复合类型),用户会 运行 陷入麻烦在类型 List_Item 中。 有两种解决方案:
- 制作 List_Item public(如果您想构建 "real" 软件,通常是一个糟糕的解决方案)
- 私密部分在
type List_Item is private
和Null_List : constant List_Item := (null, 0);
后加上Null_List : constant List_Item;
。然后你可以在 main.adb. 中使用
Null_List
确实类型是私有的,这意味着客户端 "main.adb" 不能像在 "new" 调用中那样对其内部进行假设,Zerte 的两种解决方案都解决了这个问题(并且我同意:第一个不是解决方案!)
第三种解决方案:"object factory" 设计模式。
package Linked_List is
type List_Item is private;
function Create_Item(ID_Value : Natural) return List_Item;
函数体应该是显而易见的。请注意,对于更复杂的示例,尤其是 limited private
类型,可能需要 Ada-2005 的 "extended return" 语法。
可以使用不同类型的项目的变体重载此构造函数(实际上是对象工厂的示例),并提供 Zerte 的 Null_List : constant List_Item;
作为替代。
客户端可以使用此功能
L := Create_Item(0);