You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ada无界字符串无法使用'First/'Last?是GNAT Bug还是误用?

关于Ada无界字符串'First/'Last属性的问题

问题场景

尝试获取无界字符串的首个或最后索引时,编写了如下Ada程序:

with Ada.Strings; use Ada.Strings; -- 用于`Backward`
with Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;

procedure Foo is
    package U_Str renames Ada.Strings.Unbounded;

    S : U_Str.Unbounded_String := U_Str.To_Unbounded_String ("example unbounded string");
    I : Natural := U_Str.Index (Source => S,
                                Pattern => "s",
                                Going => Backward,
                                From => S'Last);
begin
    Put_Line (I'Image);
end Foo;

使用GNAT编译时出现报错:

$ gnatmake foo.adb
x86_64-linux-gnu-gcc-10 -c foo.adb
foo.adb:12:41: prefix for "Last" attribute may not be private type
gnatmake: "foo.adb" compilation error

而使用常规String的相同逻辑程序可正常编译运行:

with Ada.Strings; use Ada.Strings; -- 用于`Backward`
with Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;

procedure Foo is
    package F_Str renames Ada.Strings.Fixed;

    S : String := "example fixed string";
    I : Natural := F_Str.Index (Source => S,
                                Pattern => "s",
                                Going => Backward,
                                From => S'Last);
begin
    Put_Line (I'Image);
end Foo;

编译运行结果:

$ gnatmake foo.adb 
x86_64-linux-gnu-gcc-10 -c foo.adb
x86_64-linux-gnu-gnatbind-10 -x foo.ali
x86_64-linux-gnu-gnatlink-10 foo.ali
$ ./foo 
 15

疑问

无界字符串是否没有'First和'Last属性?Ada参考手册仅说明数组类型或约束数组子类型可使用这些属性,未提及私有类型。这是GNAT的Bug还是遗漏了某些要点?


问题解答

  • 无界字符串确实不具备'First和'Last属性
    Ada.Strings.Unbounded.Unbounded_String是私有类型,而非数组类型。Ada语言规范明确'First、'Last这类属性仅适用于数组类型或约束数组子类型,私有类型默认不提供这些属性,因此GNAT的报错完全符合规范,并非Bug。

  • 获取无界字符串索引边界的正确方式
    要操作无界字符串的边界,需使用Ada.Strings.Unbounded包提供的专用接口:

    • 获取字符串长度:U_Str.Length(S),返回字符总数
    • 等效于S'Last的位置:直接使用U_Str.Length(S),因为Ada字符串索引默认从1开始,最后一个字符的索引等于长度
    • 等效于S'First的位置:固定为1,无需额外函数

修改后的无界字符串程序可正常运行:

with Ada.Strings; use Ada.Strings; -- 用于`Backward`
with Ada.Strings.Unbounded;
with Ada.Text_IO; use Ada.Text_IO;

procedure Foo is
    package U_Str renames Ada.Strings.Unbounded;

    S : U_Str.Unbounded_String := U_Str.To_Unbounded_String ("example unbounded string");
    I : Natural := U_Str.Index (Source => S,
                                Pattern => "s",
                                Going => Backward,
                                From => U_Str.Length(S));
begin
    Put_Line (I'Image);
end Foo;
  • 固定字符串与无界字符串的核心区别
    固定String是原生数组类型,天然继承数组的所有属性;无界字符串是封装后的私有类型,内部可能基于数组实现,但对外隐藏了底层细节,必须通过包提供的函数进行操作。

内容的提问来源于stack exchange,提问作者zorleone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:39:55