单元(Unit)可以把共用的类型、函数、过程、常量、变量等声明打包,供其他单元或主程序调用,等价于其他编程语言里的模块 / 包。
创建单元
单元分为两大核心区块:
interface 接口区:对外暴露的内容,其他文件引入后可直接访问;
implementation 实现区:内部私有代码,仅当前单元可见,外部无法调用。
例子
创建一个叫MyUnit.pas的文件,用来写其中一个单元。
unit MyUnit;
{$ifdef FPC}
{$mode objfpc}{$H+}{$J-}
{$endif}
// 接口区:对外公开
interface
procedure MyProcedure(const A: Integer);
function MyFunction(const S: string): string;
// 实现区:私有实现代码
implementation
procedure MyProcedure(const A: Integer);
begin
WriteLn('A + 10 is: ', A + 10);
end;
function MyFunction(const S: string): string;
begin
Result := S + 'strings are automatically managed';
end;
end.Code language: JavaScript (javascript)

细心的读者会发现,末尾的end. 没有对应的begin?
Pascal 的单元(
unit)语法结构和程序(program)不同
program主程序:必须有begin ... end.作为程序执行入口
unit单元:不需要全局 begin整个单元结尾:
end.(点号结尾,代表文件结束,无对应全局 begin)
interface里写函数 / 过程原型、类型、常量、全局变量:外部uses后就能调用;implementation只写函数完整实现,里面定义的局部过程、私有变量,外部单元不可见;- 单元文件以
unit 名称;开头,end.结尾。
主程序引入单元
我们的主程序文件是mydemo.pas
通过 uses 关键字加载自定义单元
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
program MyProgram;
// 引入自定义单元 MyUnit
uses
MyUnit;
begin
WriteLn(MyFunction('Note: '));
MyProcedure(5);
ReadLn;
end.Code language: PHP (php)
上面的uses 下面的MyUnit; 是单元名称,不是文件pas的名称。
也就是 是MyUnit.pas里面的第一句代码,unit MyUnit; 的这个名称。
尽管可以文件名和单元名不一样,但是建议还是让单元名和文件名同名。如果不同名,这里的uses 也是使用单元名,而不是文件名。

现在我们编译运行。主程序中调用了单元中的函数。

现在我们编译运行

编译后,读者会发现,项目目录下面,多了两个文件

.ppu(Pascal Unit File,单元编译信息文件)
仅单元文件(unit)编译才会生成,主程序 program 没有 ppu
- 存储单元
interface接口区的编译元数据:函数原型、类型、常量、导出符号; - 后续其他文件
uses MyUnit时,编译器不需要重新解析 MyUnit.pas 完整源码,直接读取.ppu快速校验接口; - 大幅提升大型项目编译速度,是 FPC 增量编译的核心文件。
MyUnit.o:MyUnit.pas 编译后的二进制机器指令(实现区完整代码)
mydemo.o:mydemo.pas 主程序的机器码
编译器先把 pas 翻译成独立二进制 .o,最后链接器把所有 .o 合并,打包成可执行程序 .exe。