Ada中的不断声明

时间:2010-07-04 11:41:01

标签: declaration ada constants

成为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的能力?这甚至可以吗?

非常感谢..

2 个答案:

答案 0 :(得分:2)

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

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

所以,回答你的问题:

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

  • 适度接近的近似值是您在此过程之外确定Stiffness_Ratio值,并将该值作为参数传递给过程。但是,Actual_Stiffness仅在程序持续时间内保持不变,而不是一直持续。

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

答案 1 :(得分:0)

在Ada中,在函数中间声明变量是完全可能和合理的。与基于C的语言的唯一区别是,必须这样做才能使作用域明确。您可以在任何地方开始作用域:

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;

例如,考虑以下Euclid的Greatest Common Divisor算法的非递归实现:

   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时一样。

在这种情况下,John Barnes在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;