玄铁模块系统
模块系统允许你将代码拆分到多个文件中,通过 引 关键字引入其他模块,通过 予 关键字为引入的模块指定别名。
基本语法
引入模块
xuantie
引 "./库/数学.xt" // 引入数学库
引 "./组件/按钮.xt" // 引入自定义组件带别名的引入
引入的模块默认使用文件名作为命名空间前缀。如果需要更短的名字,使用 予 指定别名:
xuantie
引 "./库/文件.xt" 予 文件 // 用 文件 作为别名
引 "./组件/按钮.xt" 予 btn // 用 btn 作为别名访问引入模块的成员
引入后,通过 模块名.成员名 访问模块中的函数、类型和变量:
xuantie
// math.xt 中定义了 函 平方(x) { 返 x * x }
引 "./库/数学.xt" 予 数学
设 平方值 = 数学.平方(5) // 调用模块中的函数路径解析
引 后面的路径是相对于当前源文件的路径:
xuantie
// 假设文件结构:
// project/
// main.xt
// lib/
// math.xt
// utils.xt
// ui/
// button.xt
// 在 main.xt 中:
引 "./lib/math.xt" 予 数学 // 相对路径
引 "./ui/button.xt" // 没有别名
// 在 button.xt 中:
引 "../lib/utils.xt" 予 工具 // 上级目录模块的命名空间隔离
每个被引入的模块有独立的命名空间。同名函数在不同模块中不会冲突:
xuantie
引 "./lib/math.xt" 予 数学
引 "./lib/geo.xt" 予 几何
设 a = 数学.距离(1, 2) // 调用 math.xt 中的 距离
设 b = 几何.距离(3, 4) // 调用 geo.xt 中的 距离——不冲突模块内部的函数互调
模块内部的函数可以直接用裸名互相调用,无需也不应加别名前缀——模块自己并不知道调用方给它起了什么别名:
xuantie
// ui.xt 内部:
公 函 四边(上, 右, 下, 左) { ... }
公 函 全边(值) {
返 四边(值, 值, 值, 值) // 直接裸名调用同模块函数,正确写法
}即使调用方以 引 "ui.xt" 予 UI 引入,编译器也会把模块内的裸名解析自动回退到当前模块命名空间(四边 → UI.四边)。模块内引用本模块的全局变量(设/常 声明)同样适用,且允许前向引用(函数体可以先于全局声明语句引用它)。
引入的两条硬性限制
- 同一模块在一次编译中只能使用一个别名(或都不用别名)。同一个文件先
予 R后又予 渲染,编译器会明确报错——因为模块内部的裸名互调只能映射到一个命名空间。 - 菱形引入是安全的:应用引 UI 和渲染、UI 内部又引渲染——只要别名一致,同一物理文件只预扫描、编译一次(路径最终规范化为绝对路径后去重),不会产生重复定义。
编译机制
玄铁编译器在编译时对模块的处理分两个阶段:
- 预扫描:递归读取所有
引的目标文件,收集符号(函数名、类型名、全局变量) - 合并编译:将所有模块的代码合并到同一个 LLVM 模块中,生成单一可执行文件
这意味着:
- 所有模块共享同一个全局作用域
- 循环引用会被检测并报错
- 不支持动态加载(编译时确定)
完整示例
math.xt(被引入的模块):
xuantie
// 数学工具模块
函 平方(x) { 返 x * x }
函 立方(x) { 返 x * x * x }
设 PI = 3.14159main.xt(主程序):
xuantie
引 "./math.xt" 予 数学
示("5 的平方: #{ 数学.平方(5)}")
示("5 的立方: #{ 数学.立方(5)}")
示("PI: #{ 数学.PI}")编译与运行:
xuantie
玄铁.exe tie main.xt
./main.exe
// 输出:
// 5 的平方: 25
// 5 的立方: 125
// PI: 3.14159当前局限
| 局限 | 说明 |
|---|---|
| 单别名 | 同一模块一次编译只能用一个别名,多别名会明确报错 |
| 无导出控制 | 模块中所有顶层符号默认全部导出 |
| 无循环依赖 | 循环引用被编译器检测并报错 |
| 单文件输出 | 所有模块合并为一个可执行文件 |
包管理与版本依赖等功能由铁铺(TiePM)提供,详见 07_铁铺使用指南.md。
上一篇:04_弱引用编程指南.md