您的位置:首页 >Go语言Flag包实现简单命令行备忘录
发布于2026-04-01 阅读(0)
扫一扫,手机访问
flag.String 返回指针因需在解析时直接修改变量内存地址内容;传值无法生效,解引用用*msg;子命令需手动切分os.Args并提前提取,在flag.Parse前初始化独立FlagSet。

flag.String 返回的是指针而不是值因为 flag 包需要在解析命令行时直接修改变量内存地址里的内容,如果传值,函数内部改了也没用。你声明一个 string 变量,然后用 flag.String 绑定它,本质是让 flag 在解析完后把结果写进那个变量的地址里。
常见错误:写成 msg := flag.String("msg", "", "备忘内容"),然后直接用 msg 当字符串拼接或打印——这会 panic,因为 msg 是 *string,得解引用:*msg。
msg := flag.String("msg", "", "备忘内容"); fmt.Println(*msg)flag.StringVar 配合已有变量:var msg string; flag.StringVar(&msg, "msg", "", "备忘内容")flag.String 和 flag.StringVar 行为一致,只是接口不同;后者更易读、少出错memo add -m "xxx")Go 标准库 flag 本身不支持子命令,硬套会导致参数解析混乱(比如 memo add -m "x" 中的 -m 被顶层 flag 忽略)。必须手动切分 os.Args,提前捕获第一个非 flag 参数作为子命令名。
关键点:在调用 flag.Parse() 前,先检查 os.Args 长度,并提取子命令;之后再初始化对应子命令的 flag 集合。
os.Args 调一次 flag.Parse() 就完事addCmd := flag.NewFlagSet("add", flag.ContinueOnError)flag.ContinueOnError:避免子命令解析失败时直接退出程序if len(os.Args) < 2 { log.Fatal("subcommand required") }; cmd := os.Args[1]; if cmd == "add" { addCmd.Parse(os.Args[2:]) }flag.Parse() 之后还能再解析别的参数吗不能。每个 flag.FlagSet 实例只能调用一次 Parse(),重复调用会 panic:flag provided but not defined: -xxx。这是设计使然——Parse() 会消费掉所有匹配的参数,并把剩余非 flag 参数存进 FlagSet.Args()。
如果你需要多次解析(比如主命令 + 子命令),必须用多个独立的 flag.FlagSet 实例,各自调用一次 Parse()。
flag.CommandLine,子命令用 flag.NewFlagSet-xxx 就是上次没被识别的残留参数命令行工具默认没状态,每次运行都是新进程,所以必须持久化到文件。用 JSON 是合理选择,但 Go 的 json.Marshal 默认导出首字母大写的字段,小写字段会被忽略——这意味着结构体字段必须大写且加 json: tag,否则写进去的是空对象。
另一个坑是并发:如果用户快速连发两条 memo add,可能两个进程同时读-改-写同一文件,导致丢失数据。简单 CLI 工具可暂不处理并发,但至少要加 os.O_APPEND 或全量重写时用临时文件 + os.Rename 避免中间态损坏。
type Note struct { Text string `json:"text"`; Time string `json:"time"` }ioutil.WriteFile 到临时路径,再 os.Rename 替换原文件,保证原子性os.IsNotExist(err),首次运行要容忍空文件或不存在flag.String 接收文件路径然后直接 os.Open——用户可能输错路径,记得加错误处理下一篇:苹果手机关闭系统广告推荐方法
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9