Ada 中的常量声明

问题描述 投票:0回答:2

作为 Ada 新手,我正在探索它的语法和规则,我想提请注意接下来给出的代码。在这里,我尝试设置变量 Actual_Stiffness 来保持恒定值。其价值由产品给出:

Actual_Stiffness := Stiffness_Ratio * Stiffness_Total

其中 Stiffness_Total 已在规范文件 Material_Data.ads 中定义为常量 Long_Float,并且 Stiffness_Total 已在广告文件中设置值。

WITH Ada.Text_IO;
WITH Ada.Long_Float_Text_IO;
WITH Material_Data;
USE Material_Data;

PROCEDURE sample IS

   Stiffness_Ratio  : Long_Float;
   Actual_Stiffness : CONSTANT Long_Float :=  Stiffness_Ratio * Stiffness_Total;

BEGIN -- main program
   Ada.Text_IO.Put("Enter stiffness ratio: ");
   Ada.Long_Float_Text_IO.Get(Item => Stiffness_Ratio);
   Ada.Long_Float_Text_IO.Put(Item => Stiffness_Ratio);

   --Ada.Text_IO.New_Line;
   --Ada.Long_Float_Text_IO.Put(Item => Actual_Stiffness);
   --Ada.Text_IO.New_Line;
   --Ada.Long_Float_Text_IO.Put(Item => Stiffness_Total);
END sample;

编译时我收到警告消息

警告:“Stiffness_Ratio”可能在获得值之前被引用

并且在运行程序时,Actual_Stiffness 没有获得正确的值。我可以将 Actual_Stiffness 定义为 Long_Float (不添加 CONSTANT),然后在程序中的 BEGIN 之后从产品 Actual_Stiffness := Stiffness_Ratio * Stiffness_Total 中获取其值,此时 Stiffness_Ratio 已经获得了值。这是正确的做法。

我的问题是:

我已将 Stiffness_Total 定义为具有规定值的常量 Long_Float。如何将 Actual_Stiffness 定义为常量(因为它不会在程序中更改),同时保持用户能够在终端交互地输入 Stiffness_Ratio 的能力?这可能吗?

非常感谢..

declaration ada constants
2个回答
4
投票

由于“Stiffness_Ratio”直到运行时才确定,编译器无法按照您的要求在编译时计算“Actual_Stiffness”的值。您必须将“Actual_Stiffness”设为非常量变量,并在“Stiffness_Ratio”获得值后通过计算对其进行初始化。 (只要刚度比在计算实际刚度时有一个值,您甚至可以将其保持为函数内的常量。)

这是大多数编程语言的标准。

所以,回答你的问题:

  • 不,您无法根据需要将 Actual_Stiffness 定义为常量。

  • 一个适度接近的近似是您在此过程之外确定 Stiffness_Ratio 值,并将该值作为参数传递到该过程中。但实际刚度仅在手术期间保持不变,而不是始终保持不变。

另一方面,这可能更有用;有人可以在不同时间使用多个刚度比值运行程序,从而在一次运行中进行多次模拟。


4
投票

在 Ada 中,在函数中间声明变量是完全可能且合理的。就像在所有其他编程语言(至少 Java、C、C++、C#、python)中一样,您可以在任何地方显式创建作用域:

declare
   A : My_Type := Val;
begin
   Use(A);
end;

这意味着您的常量可以在收到运行时值后声明:

WITH Ada.Text_IO;
WITH Ada.Long_Float_Text_IO;
WITH Material_Data;
USE Material_Data;

PROCEDURE sample IS

   Stiffness_Ratio  : Long_Float;

BEGIN -- main program
   Ada.Text_IO.Put("Enter stiffness ratio: ");
   Ada.Long_Float_Text_IO.Get(Item => Stiffness_Ratio);
   Ada.Long_Float_Text_IO.Put(Item => Stiffness_Ratio);

   --Ada.Text_IO.New_Line;
   declare
      Actual_Stiffness : CONSTANT Long_Float :=  Stiffness_Ratio * Stiffness_Total;
   begin
      Ada.Long_Float_Text_IO.Put(Item => Actual_Stiffness);
   end;
   --Ada.Text_IO.New_Line;
   --Ada.Long_Float_Text_IO.Put(Item => Stiffness_Total);
END sample;

关于充分利用块作用域变量的另一个示例,请考虑以下欧几里得最大公约数算法的非递归实现,其中新的 X 和 Y 声明隐藏了形式参数:

   function GCD(X,Y : Integer) return Integer is
   begin
      declare
         X : Integer := GCD.X;
         Y : Integer := GCD.Y;
      begin
         while Y /= 0 loop
            declare
               temp : Integer := X;
            begin
               X := Y;
               Y := temp mod Y;
            end;
         end loop;
         return X;
      end;
   end GCD;

在 GCD 中,形式参数 X 和 Y 始终是常量,因为它们被声明为

in
。这是为了避免混淆;如果我们允许给变量赋值,程序员可能会认为他造成了副作用,就像参数被标记为
out
的情况一样。因此,我们不能简单地修改现有的 X 和 Y,就像我们在许多其他编程语言中可能会做的那样。

John Barnes 的《Programming in Ada 2012》建议在这种情况下在函数本身的范围内声明一个具有不同名称的变量。第 194 页,第 11.2 节:

   function Sum(List: Cell_Ptr) return Integer is
      Local: Cell_Ptr := List;
      (...)

这使得程序员能够引用List,即常量且未更改的初始值。在上面给出的 GCD 程序的情况下,在循环体中引用该值将导致不正确的行为。

通过添加具有相同名称的变量的内部作用域来隐藏 X 和 Y 意味着我们需要显式包含变量的作用域才能犯该错误。尝试在循环体中将

X := Y
更改为
X := GCD.Y
,并观察 GCD(91,21) 现在返回 21 而不是 7。

最后,请注意,内部作用域可以通过在前面添加标签来命名:

   Inner:
   declare
      X : Integer := 0;
   begin
      Use(Inner.X); -- explicitly the X in that scope
   end Inner;
© www.soinside.com 2019 - 2024. All rights reserved.