|
|
1 день назад | |
|---|---|---|
| .. | ||
| README.md | 1 день назад | |
| main.go | 1 день назад | |
| main_test.go | 1 день назад | |
让程序从命令行参数或键盘取得姓名、学习分钟数,理解 os.Args、flag、标准输入输出与基本校验。先看 main.go,运行两种模式,再看 main_test.go。
本课只使用标准库,共享根目录的 go.mod,无需安装依赖;不会写入或修改学习记录文件。当前程序每次运行只处理一条记录,后续综合项目再结合 JSON 存储。
在仓库根目录的 PowerShell 执行:
New-Item -ItemType Directory -Force bin/19_cli | Out-Null
go build -o ./bin/19_cli/study.exe ./lessons/19_cli
修改源码后需要重新编译。后面的 study.exe 命令均假设终端仍在仓库根目录。
.\bin\19_cli\study.exe -name 小朱 -minutes 30
输出:
学习者:小朱,学习时长:30 分钟
姓名包含空格时加引号:
.\bin\19_cli\study.exe -name "小 朱" -minutes 45
不提前编译也能使用 go run,它仍会先编译再运行:
go run ./lessons/19_cli -name 小朱 -minutes 30
参数写在包路径之后。也可以写 -name=小朱 -minutes=30。不提供姓名或分钟数、分钟数不在 1~1440 之间、整数格式错误,都会报告错误并以非零状态退出。
查看帮助:
.\bin\19_cli\study.exe -h
-h / -help 在本程序中显示帮助并正常结束。参数错误由 flag 输出提示,本程序再输出错误摘要;因此有时会看到两部分信息。
.\bin\19_cli\study.exe -interactive
按提示输入两行:
请输入姓名:小朱
请输入学习分钟数:45
学习者:小朱,学习时长:45 分钟
输入的姓名和分钟数会去掉两端空白。空姓名、非整数或超范围分钟数会报错,不会重复要求输入;结束后重新运行即可。
也可以把输入传给程序,例如 PowerShell:
"小朱", "45" | .\bin\19_cli\study.exe -interactive
管道中不会像交互终端一样回显你输入的每一行,因此提示和结果可能显示在同一行。实际终端编码依赖 Windows / PowerShell 配置,出现乱码时先检查终端编码。
两种输入来源不可混用:-interactive 不能同时显式指定 -name 或 -minutes,即使它们的值是空字符串或 0 也不行。帮助中布尔选项单独写 -interactive 等价于 -interactive=true;-interactive=false 表示参数模式。
os.Args[0] // 通常是程序名或可执行文件路径。
os.Args[1:] // 用户输入的参数,不含程序名。
参数原始上是字符串切片。标准库 flag 根据声明解析带名称的参数,避免自己逐个处理 -name 之类的文本。
name := flags.String("name", "", "学习者姓名")
minutes := flags.Int("minutes", 0, "学习时长")
String 返回 *string、Int 返回 *int,所以使用时写 *name、*minutes。解析成功后它们指向保存解析结果的变量。第九课学过的 * 是解引用,不是乘法。
flag.NewFlagSet 创建独立解析器,flag.ContinueOnError 让 Parse 返回错误,便于调用者和测试处理。flags.SetOutput 只控制 flag 产生的帮助/解析提示;本课 main 额外将业务错误输出到标准错误。
flags.Visit 遍历显式设置过的选项。本例借它区分“没有设置”和“明确设置为默认值”,用于禁止混合输入。它的回调是第十三课学过的函数参数,不需要在这里记住完整接口。
flag 遇到第一个非 flag 位置参数后停止解析;本例用 NArg 检查并拒绝所有位置参数,因此请把选项写在前面,避免将输入误当作合法参数。单独的 -- 会结束选项解析,后续内容也是位置参数,在本例会被拒绝。
os.Stdin:标准输入,交互时通常连接键盘,也可以来自管道。os.Stdout:标准输出,正常结果写到这里。os.Stderr:标准错误,main 将最终错误写到这里。io.Reader 和 io.Writer 是第十六课的接口,让函数可以接收终端,也可以接收测试中准备的输入输出。交互模式用 bufio.Scanner 逐行读取,Scan 后检查 Err,正常输入提前结束也会报错。Scanner 有默认单行大小限制;不适合无上限的输入。
测试中 strings.NewReader 模拟输入,bytes.Buffer 保存输出,不需要测试时真实敲键盘。这个程序的 flag 解析帮助信息写到传入的 output;若要更细致地区分标准输出和标准错误,可以进一步分别注入两个 writer。
main 遇到非帮助错误时输出错误并调用 os.Exit(1)。PowerShell 运行 exe 后,可检查 $LASTEXITCODE:0 表示正常退出,非 0 表示失败。
.\bin\19_cli\study.exe -name 小朱 -minutes 0
$LASTEXITCODE
os.Exit 不执行当前进程已登记的 defer。本例 run 已经返回,且没有需要释放的外部资源;以后涉及文件或网络时,应先关闭资源,再决定是否退出。
在仓库根目录执行:
go test -count=1 -v ./lessons/19_cli
测试覆盖参数模式、交互模式、帮助、空输入、混用模式、参数错误和时长边界,不需要人工输入。
-topic 参数,并为它补测试。若另行手敲,放到本课的 practice 子目录,用 go run ./lessons/19_cli/practice -name 小朱 -minutes 30 运行,不要在同一个包里重复声明 main 或 run。
下一课学习 HTTP 客户端与简单服务,让程序通过网络交换数据。