构建一个 CLI 工具
本教程带你用 Zerolang 构建一个完整的命令行工具。你将创建包、解析参数、读写文件、处理错误,并交叉编译到 Linux。
前置条件:已安装 Zerolang(zero --version 正常工作)。
时间:约 30 分钟
第一步:创建包
zero new cli mytool
cd mytool
创建如下结构:
mytool/
├── zero.json
└── src/
└── main.0
zero.json 清单:
{
"package": { "name": "mytool", "version": "0.1.0" },
"targets": { "cli": { "kind": "exe", "main": "src/main.0" } }
}
第二步:读取命令行参数
编辑 src/main.0:
use std.args
pub fn main(world: World) -> Void raises {
let name: Maybe<String> = std.args.get(1)
if name.has {
check world.out.write("Hello, " + name.value + "!\n")
} else {
check world.out.write("Usage: mytool <name>\n")
}
}
std.args.get 返回 Maybe<String>,因为参数可能不存在。使用 .has 检查是否存在,.value 访问值。
运行:
zero run src/main.0 -- Alice
输出:Hello, Alice!
不带参数:
zero run src/main.0
输出:Usage: mytool <name>
第三步:写入文件
use std.args
use std.fs
pub fn main(world: World) -> Void raises {
let name: Maybe<String> = std.args.get(1)
if name.has {
let output: String = "Hello, " + name.value + "!\n"
let written: usize = std.fs.write("output.txt", output)
if written > 0 {
check world.out.write("Wrote " + name.value + " to output.txt\n")
}
} else {
check world.out.write("Usage: mytool <name>\n")
}
}
std.fs.write 是宿主 API — 在宿主目标上工作,但在非宿主目标上报告 TAR002。
第四步:显式处理错误
Zero 的错误处理使用 raises 和 check。可能失败的函数声明 raises:
use std.args
use std.fs
fn writeGreeting(name: String) -> Void raises [Io] {
let output: String = "Hello, " + name + "!\n"
let written: usize = std.fs.write("output.txt", output)
if written == 0 {
raise Io
}
}
pub fn main(world: World) -> Void raises [Io] {
let name: Maybe<String> = std.args.get(1)
if name.has {
writeGreeting(name.value)
check world.out.write("Done\n")
} else {
check world.out.write("Usage: mytool <name>\n")
}
}
raises [Io] 声明告诉编译器(以及任何阅读代码的 Agent)这个函数能产生哪些错误。
第五步:添加测试
在 src/main.0 中添加测试块:
test "greeting format" {
let greeting: String = "Hello, " + "Zero" + "!\n"
expect (greeting == "Hello, Zero!\n")
}
运行测试:
zero test src/main.0
第六步:构建可执行文件
zero build --emit exe --target host src/main.0 --out ./mytool
这会生成原生可执行文件。运行:
./mytool Alice
第七步:交叉编译到 Linux
zero build --emit exe --target linux-musl-x64 src/main.0 --out ./mytool-linux
检查目标就绪性:
zero doctor --json
输出显示宿主检查结果、targetToolchains 和逐目标就绪矩阵。
第八步:检查二进制大小
zero size --json src/main.0
输出包含:
graph— 图标识信息profileSemantics— 配置语义profileCatalog— 配置目录profileBudget— 配置预算safetyFacts— 安全性事实backendProfile— 后端配置backendComparison— 后端对比sizeBreakdown— 每个段的大小retentionReasons— 为什么保留每个辅助工具optimizationHints— 减小大小的建议
第九步:让 Agent 检查代码
zero check --json src/main.0
如果有问题,Agent 读取结构化诊断并应用修复:
zero fix --plan --json src/main.0
完整的包
最终的 src/main.0:
use std.args
use std.fs
fn writeGreeting(name: String) -> Void raises [Io] {
let output: String = "Hello, " + name + "!\n"
let written: usize = std.fs.write("output.txt", output)
if written == 0 {
raise Io
}
}
pub fn main(world: World) -> Void raises [Io] {
let name: Maybe<String> = std.args.get(1)
if name.has {
writeGreeting(name.value)
check world.out.write("Done\n")
} else {
check world.out.write("Usage: mytool <name>\n")
}
}
test "greeting format" {
let greeting: String = "Hello, " + "Zero" + "!\n"
expect (greeting == "Hello, Zero!\n")
}
你学到了什么
- 包:
zero new创建带zero.json和src/的包 - 参数:
std.args.get返回Maybe<String>以安全访问 - 文件 I/O:
std.fs.write用于宿主文件操作 - 错误处理:
raises、check和命名错误集 - 测试:带
expect断言的test块 - 构建:
zero build --emit exe生成原生可执行文件 - 交叉编译:
--target linux-musl-x64生成 Linux 二进制文件 - 大小检查:
zero size用于二进制分析 - Agent 工作流:
zero check --json和zero fix --plan --json
延伸阅读
- CLI 参考 — 所有命令
- 标准库 — 更多模块
- 让 Agent 编辑你的代码 — Agent 工作流