第3课|第一个Ada程序:Hello World深入解析

本课目标

完成本课后,你将能够:

  • 完整理解Ada程序的结构与语法元素

  • 掌握 with 子句的多种用法和作用域规则

  • 正确使用Ada的标识符、保留字和注释规范

  • 区分声明部分与执行部分的职能边界

  • 编写符合工业标准的规范Ada代码


一、程序结构全景解析

1.1 Hello World的完整解剖

回顾上节课的代码:

ada 复制代码
with Ada.Text_IO;

procedure Hello is
   -- 声明部分(Declarative Part)
begin
   -- 执行部分(Executable Part)
   Ada.Text_IO.Put_Line ("Hello, Ada World!");
end Hello;

Ada程序的四大组成部分

部分 关键字 作用 可否为空
上下文子句 with / use 引入外部依赖 可以
单元头 procedure / function / package 程序单元类型和名称 不可
声明部分 isbegin 之间 局部常量、变量、类型、子程序 可以
执行部分 beginend 之间 实现具体逻辑 不可

1.2 最简单的合法程序

ada 复制代码
procedure Minimal is
begin
   null;  -- 空语句,表示"什么都不做"
end Minimal;

null 语句是Ada的占位符,用于语法上必须有语句但逻辑上无需操作的场景。


二、上下文子句深度解析

2.1 with 子句的本质

with 不是简单的"文件包含",而是语义化的单元依赖声明

ada 复制代码
with Ada.Text_IO;           -- 引入标准输入输出包
with Ada.Integer_Text_IO;   -- 引入整数输入输出包
with Ada.Float_Text_IO;     -- 引入浮点数输入输出包

与C语言 #include 的核心区别:

特性 C #include Ada with
机制 文本替换 语义检查
重复引用 需用 #ifndef 防护 自动处理,无重复问题
依赖分析 预处理器处理 编译器原生支持,可精准追踪
信息隐藏 头文件暴露所有细节 规范(.ads)控制可见性

2.2 use 子句:简化访问

频繁使用 Ada.Text_IO.Put_Line 很冗长,可用 use

ada 复制代码
with Ada.Text_IO;
use Ada.Text_IO;  -- 将包的内容直接引入当前作用域

procedure Greetings is
begin
   Put_Line ("Hello!");      -- 无需前缀
   Put_Line ("Goodbye!");    -- 直接调用
end Greetings;

对比两种风格

风格 代码 适用场景
全限定 Ada.Text_IO.Put_Line (...) 大型项目,避免命名冲突
use字句 Put_Line (...) 小型程序,提高可读性

工业建议 :规范文件(.ads)中避免 use ,包体(.adb)中可酌情使用。


2.3 use type :精确控制

只想引入某个类型的操作符,而非整个包:

ada 复制代码
with Ada.Calendar;
use type Ada.Calendar.Time;  -- 只引入Time类型的操作符

procedure Time_Example is
   T1, T2 : Ada.Calendar.Time;
begin
   if T1 < T2 then  -- 可直接使用<操作符
      ...
   end if;
end Time_Example;

三、标识符与保留字

3.1 标识符命名规则

ada 复制代码
-- 合法标识符
Hello_World
Get_Value
Temperature_2
HTTP_Request   -- 连续下划线非法!应为HTTP_Request或Http_Request

-- 非法标识符
2nd_Value      -- 数字开头
Get-Value      -- 连字符非法(这是减号)
Hello__World   -- 连续下划线非法
hello world    -- 空格非法

Ada标识符规则

  • 必须以字母开头

  • 只能包含字母、数字、下划线

  • 不能连续使用两个下划线

  • 不能以数字开头

  • 不区分大小写HelloHELLO 相同)


3.2 保留字(关键字)

Ada有73个保留字,不可用作标识符:

类别 保留字
声明 procedure , function , package , type , subtype , constant
控制 if , then , else , elsif , case , when , loop , while , for , exit , return
并发 task , entry , accept , select , delay , abort
异常 exception , raise , begin , end
其他 is , in , out , access , new , null , others

完整列表见Ada Reference Manual


3.3 命名规范(工业标准)

元素 规范 示例
包/过程/函数 PascalCase Ada.Text_IO , Get_Value
变量/常量 Snake_Case current_temperature , Max_Size
常量 大写PascalCase PI , Buffer_Size
类型/子类型 PascalCase Integer , Positive , My_Record

四、注释与文档

4.1 单行注释

ada 复制代码
-- 这是单行注释,从--到行尾
X := 10;  -- 行尾注释,解释X的初始值

4.2 多行注释(Ada无原生支持)

Ada标准没有 /* */ 风格的多行注释,需每行加 --

ada 复制代码
-- 这是第一段说明
-- 这是第二段说明
-- 这是第三段说明
X := 20;

历史原因:Ada设计于1980年,当时认为多行注释容易导致注释嵌套混乱,且不利于工具处理。

4.3 文档注释(AdaDoc风格)

ada 复制代码
-- 计算圆的面积
-- 参数:
--   Radius - 圆的半径,必须为正数
-- 返回:
--   圆的面积
function Circle_Area (Radius : Float) return Float is
begin
   return 3.14159 * Radius ** 2;
end Circle_Area;

五、声明部分详解

5.1 可以声明什么?

ada 复制代码
procedure Declarations is
   
   -- 1. 常量声明
   Pi : constant Float := 3.14159;
   
   -- 2. 变量声明
   Counter : Integer := 0;
   
   -- 3. 类型声明
   type Day is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
   
   -- 4. 子类型声明
   subtype Weekday is Day range Mon .. Fri;
   
   -- 5. 子程序声明(前向声明)
   procedure Helper (X : in out Integer);
   
   -- 6. 其他包的使用
   package My_IO renames Ada.Text_IO;
   
begin
   -- 执行部分可以使用上述所有声明
   Counter := Counter + 1;
   Helper (Counter);
end Declarations;

-- 子程序体必须在主单元之后或单独文件中
procedure Helper (X : in out Integer) is
begin
   X := X * 2;
end Helper;

__

5.2 声明的顺序规则

重要 :Ada要求先声明后使用

ada 复制代码
procedure Order_Matters is
   A : Integer := B;  -- ERROR! B尚未声明
   B : Integer := 10;
begin
   null;
end Order_Matters;

正确写法

ada 复制代码
procedure Correct_Order is
   B : Integer := 10;  -- 先声明B
   A : Integer := B;   -- 再使用B,合法
begin
   null;
end Correct_Order;

六、执行部分详解

6.1 语句序列

beginend 之间是语句序列,每条语句以分号结束:

ada 复制代码
procedure Statements is
begin
   -- 过程调用语句
   Ada.Text_IO.Put_Line ("First");
   
   -- 赋值语句
   X := 10;
   
   -- 控制语句
   if X > 5 then
      Ada.Text_IO.Put_Line ("Big");
   end if;
   
   -- 空语句(合法但无操作)
   null;
end Statements;

6.2 语句的终止

元素 是否需要分号 示例
语句 必须 X := 10;
声明 必须 A : Integer;
end 必须 end Hello;
begin 不需要 begin
loop , if , then 不需要 if X > 5 then

七、完整示例:温度转换器

ada 复制代码
-- 文件名: temperature_converter.adb
-- 功能:摄氏度与华氏度相互转换

with Ada.Text_IO;
with Ada.Float_Text_IO;

procedure Temperature_Converter is
   
   -- 常量声明
   Freezing_C : constant Float := 0.0;
   Freezing_F : constant Float := 32.0;
   Factor     : constant Float := 5.0 / 9.0;
   
   -- 变量声明
   Celsius    : Float;
   Fahrenheit : Float;
   
begin
   
   -- 摄氏度转华氏度
   Celsius := 100.0;
   Fahrenheit := Freezing_F + Celsius / Factor;
   
   Ada.Text_IO.Put ("Celsius: ");
   Ada.Float_Text_IO.Put (Celsius, Fore => 3, Aft => 1, Exp => 0);
   Ada.Text_IO.Put (" => Fahrenheit: ");
   Ada.Float_Text_IO.Put (Fahrenheit, Fore => 3, Aft => 1, Exp => 0);
   Ada.Text_IO.New_Line;
   
   -- 华氏度转摄氏度
   Fahrenheit := 212.0;
   Celsius := Factor * (Fahrenheit - Freezing_F);
   
   Ada.Text_IO.Put ("Fahrenheit: ");
   Ada.Float_Text_IO.Put (Fahrenheit, Fore => 3, Aft => 1, Exp => 0);
   Ada.Text_IO.Put (" => Celsius: ");
   Ada.Float_Text_IO.Put (Celsius, Fore => 3, Aft => 1, Exp => 0);
   Ada.Text_IO.New_Line;
   
end Temperature_Converter;

编译运行

bash 复制代码
gnatmake temperature_converter.adb
./temperature_converter

输出

text 复制代码
Celsius: 100.0 => Fahrenheit: 212.0
Fahrenheit: 212.0 => Celsius: 100.0

八、常见编译错误速查

错误信息 原因 解决
missing ";" 语句末尾缺少分号 添加 ;
incorrect use of "with" with 子句位置错误 移到最开头
identifier cannot be use clause name use 后直接跟包名,缺少 ; with P; use P;
declaration expected 声明部分写了执行语句 移到 begin
statement expected begin 后写了声明 移到 isbegin 之间

九、本课总结

  • Ada程序由上下文子句、单元头、声明部分、执行部分四部分组成

  • with 引入依赖, use 简化访问,规范中避免 use

  • 标识符不区分大小写,不能连续下划线,不能以数字开头

  • 注释只有 -- 单行形式,文档化注释需每行加 --

  • 先声明后使用是铁律 ,声明在 isbegin 之间,执行语句在 beginend 之间


十、课后练习

1.修正错误:以下代码有3处错误,找出并修正:

ada 复制代码
procedure Broken is
begin
   with Ada.Text_IO;
   Ada.Text_IO.Put_Line ("Test")
end broken;

2.规范命名:将以下不规范标识符改为Ada标准形式:

getValue → ?

2nd_item → ?

HTTP__Request → ?

3.扩展程序:修改温度转换器,增加开尔文温度转换(K = C + 273.15)。

4.代码风格 :重写Hello World,使用 use Ada.Text_IO; ,对比可读性差异。


十一、下节预告

第4课|程序结构与编译流程

我们将:

  • 理解库单元、子单元、主程序的层级关系

  • 掌握 gnatmake 的依赖分析原理

  • 学习分离编译与分别编译的区别

  • 构建第一个多文件Ada项目


关键术语表

  • 上下文子句withuse 子句的统称,用于管理单元依赖

  • 声明部分isbegin 之间的区域,用于定义局部实体

  • 执行部分beginend 之间的区域,包含实际执行的语句

  • 保留字:Ada语言预定义的关键字,不可用作标识符

  • 前向声明:先声明子程序签名,稍后提供实现的机制


提示警告:本课程内容(包括但不限于文字、图片、音频、视频等)版权归原作者所有,未经授权严禁转载、复制、翻录、传播或以任何方式用于商业用途。本课程仅供个人学习使用,请尊重知识产权,共同维护良好的创作环境。如有疑问或需授权合作,请联系版权方。感谢您的理解与支持!

相关推荐
Java编程爱好者2 小时前
为什么 Spring 和 IDEA 都不推荐使用 @Autowired 注解??
后端
Java编程爱好者2 小时前
Spring Boot + JPackage:构建独立安装包!
后端
CS生3 小时前
Rust环境准备
开发语言·后端·rust
神奇小汤圆3 小时前
效率拉爆:IntelliJ IDEA 中的这几款 AI 编程插件你都用过吗?
后端
小志biubiu3 小时前
Linux_进程概念(A)-进程部分【Ubuntu】
linux·运维·服务器·ubuntu·操作系统·进程
神奇小汤圆3 小时前
都2026年了,还在用Xshell?试试这几款现代化的终端工具吧!
后端
understandme3 小时前
记录 redis 端口的坑,高并发请求常见的问题分类
后端
折七3 小时前
2026 年 Node.js 后端技术选型,为什么我选了 Hono 而不是 NestJS
前端·后端·node.js