为什么字符串需要初始化一个初始值?

Why do strings need to be initialized with an initial value?

我有一个字符串 lx : String,我想稍后在我的代码中设置该值,但我收到错误 unconstrained subtype not allowed (need initialization) provide initial value or explicit array bounds

我还有一个字符串数组L_array : array (1 .. user_size) of String;,它抛出错误unconstrained element type in array declaration。我无法从一开始就对其进行初始化,因为这些值是从文本文件中读入的。如果我想稍后设置这些值,我该怎么办?

Ada 的字符串类型定义为 type String is array(Positive range <>) of Character。这需要一个初始范围来声明一个变量,通过given an initial string or given a range constraint,否则编译器将无法知道对象有多大。

查看 Rosettacode 中的示例,了解如何从文件中读取。

这里确实有两个问题,但具有相同的根本原因:String 在创建时必须固定其大小(即约束)。

如果您知道它的大小,并且(在 array of String 的情况下)所有 String 的大小都相同,那么限制它们很容易,不需要进一步的评论。

想想 String 未知长度意味着什么:未知的存储要求。一种方法是使用指针或访问类型,分配存储空间来保存字符串,并记得稍后释放它。与其他语言一样,这种方式可能会出现错误、内存泄漏等。猜测大小上限的替代方法也是如此,这会带来缓冲区溢出的可能性。您可以像在其他语言中一样在 Ada 中执行此操作,但是...不是最佳实践。

Ada 分别以 Unbounded_StringBounded_String 的形式提供了对这两种模式的抽象,旨在最大限度地减少问题。但是使用起来还是不如String.

有一个 somewhat intense discussion of these abstractions on the comp.lang.ada 新闻组(我很抱歉使用 Google Groups 网关)

因此,我将建议您使用 String.

完成这两项任务的方法

对于稍后设置值的单个字符串 lx : String 的情况,答案很简单:只需稍后声明 String,用该值初始化。而不是

lx : String;

...
lx := Read(My_File);
Process_String(lx);

使用声明块(通常在循环体中):

...    
declare
   lx : String := Read(My_File);
begin
   Process_String(lx);
end;

end 处,字符串 lx 超出范围,并重新创建(具有正确的大小,从初始化开始,下次到达 declare 块时。


如果每个成员的大小不同,Array of String 会更难,Bounded_StringUnbounded_String 是有用的候选者。

但是另一种方法(自 Ada-2005 起)是使用 Ada.Containers 包而不是数组。它们有 Definite 和 Indefinite 两种类型,您需要一个 Indefinite 容器来存储不同大小的成员。具体来说 Ada.Containers.Indefinite_Vectors 作为 Vector 可以像 Array 一样进行索引。

这种方式与在C++中使用std_vector有相似之处,实际上标准模板库最初是为Ada设计的,后来适应了C++。

在 Ada-2005 之前,Ada.Containers 不是该语言的一部分,但您可以使用来自外部库的等效项,例如(我认为)Booch 组件 (Grady Booch)。

首发:

with Ada.Containers.Indefinite_Vectors;
with Ada.Text_IO; 

procedure String_Vector is

User_Size : constant natural := 10;
subtype Index is natural range 1 .. User_Size;

-- Indefinite_Vectors is a generic package. 
-- You can't use it directly, instantiate it with index and content types
package String_Holder is new Ada.Containers.Indefinite_Vectors(Index,String);
-- make String_Holder operations visible
use String_Holder; 

LV       : String_Holder.Vector;        -- initially empty
L_Vector : String_Holder.Vector :=      -- initialise to size with empty elements
          To_Vector(Ada.Containers.Count_Type(User_Size)); 


begin
   L_Vector.Replace_Element(1,"hello");
   LV.Append("world");
   Ada.Text_IO.Put_Line(L_Vector(1) & " " & LV(1));
end String_Vector;