Ada中的自定义“图像属性”是什么?

7

我有一个问题。

type Thing is new record
  ...elements...
end record;

我有一个将其转化为字符串的函数。
function ToString(t: Thing) returns string;

我希望能够告诉Ada使用此函数来处理Thing'image,这样我的库的用户就不必考虑他们是否正在使用内置类型或Thing。但是,显然的语法:
for Thing'image use ToString;

这个功能无法使用。

有没有其他的方法可以实现这个功能?

3个回答

9
我不知道为什么这种语言不支持这个功能,也不知道是否有人曾经提出过正式的建议(Ada问题或AI)。与此相关的 AI12-0020(Ada 2012的第20个AI)中包含了这样一句话:“我认为我们之所以没有因技术原因而拒绝它,更多的是因为重要性。”
你可以看到为什么Ada联合委员会可能认为这相对不重要:你总可以声明一个Image函数;区别在于
Pkg.Image (V);

并且

Pkg.Typ’Image (V);

不是很大。


2
真是太遗憾了。在一个非常一致的语言中,这是一个令人讨厌的不一致之处 --- 在一个体面的编程语言中,用户定义的类型不应该是二等公民构造。(此外,我的程序与GNAT绑定,因此能够执行V'img将非常有用。) - David Given
1
我倾向于使用通用包来创建一个签名 [类型 + 图像函数],然后通过这种方式访问图像函数。(这允许根据实例化调用不同的to_string函数; 即调试字符串函数或简单的to_string函数。) - Shark8
2
事实上,我最终做的是重载 &,这样我就可以无缝地将我的对象附加到字符串中。由于我大多数时候都想在构建向用户发送的消息时这样做,因此这对我大多数目的来说已经足够了。但这并不是一个真正的解决方案。 - David Given

2
Ada 2022现在支持所有类型的Image属性。它在大多数情况下表现良好,并且可以重新定义。然而,它只受以下编译器版本的支持:
  • GCC 12、13、14(使用Text_Buffers)
  • GNAT Community Edition 2021(使用Text_Buffers)
  • GNAT Community Edition 2020(使用Text_Output.Utils)
  • GCC 11(使用Text_Output.Utils)
要重新定义您类型的Image属性,您需要添加Put_Image方面,并引用您自定义的Image过程。第一个参数是Root_Buffer_Type'Class文本缓冲区,根据您的GNAT版本不同,它可能定义在Text_BuffersText_Output.Utils中。由于此功能仅在Ada 2022及更高版本中受支持,可能还需要Ada_2022编译指示或构建标志。
pragma Ada_2022;

with Ada.Text_IO;
with Ada.Strings.Text_Buffers;

procedure Main is

   type Source_Location is record
      Line   : Positive;
      Column : Positive;
   end record
     with Put_Image => My_Put_Image;

   procedure My_Put_Image
     (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
      Value  : Source_Location);

   procedure My_Put_Image
     (Output : in out Ada.Strings.Text_Buffers.Root_Buffer_Type'Class;
      Value  : Source_Location)
   is
      Line   : constant String := Value.Line'Image;
      Column : constant String := Value.Column'Image;
      Result : constant String :=
        Line (2 .. Line'Last) & ':' & Column (2 .. Column'Last);
   begin
       Output.Put (Result);
   end My_Put_Image;

   Line_10 : constant Source_Location := (Line => 10, Column => 1);

begin
   Ada.Text_IO.Put_Line (Line_10'Image);
end Main;

不清楚是否可以直接重新定义外部或Ada标准库中定义的类型的Image。然而,可以为它们的子类型和派生类型重新定义Image。
type Special_Interest is new Integer with Put_Image => Special_Interest_Image;

1
一种常见的方法是创建一个一元加函数...
    function "+"(item : myType) return String;

这个语法非常简洁。

显而易见的免责声明:在应用于数字类型时可能会导致一些歧义(例如Put (+4))。

然而,仍然存在预定义类型和用户自定义类型之间的区别。 但是,除非您指定一个强制执行此函数存在的接口(如果客户端调用了未定义“img”函数的私有类型的“img”),否则您的客户端代码将无法使用“img”。

如果最终需要一个接口,函数叫什么并不重要。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接