Golang实现一个最简单的命令行程序示例

Go程序入口func main()必须位于package main中,签名固定为无参数无返回值,且一个目录下只能有一个;使用flag包解析命令行参数需调用flag.Parse(),支持--name=Tom等格式,不支持位置参数。

main 函数必须在 package main 里

Go 程序入口是 func main(),它只能出现在 package main 中。如果写成其他包名(比如 package cmd),go run 会报错:cannot run non-main package。这不是语法错误,而是构建约束——Go 编译器直接拒绝执行。

实操建议:

  • 新建文件时第一行必须是 package main
  • main 函数不能带参数、不能有返回值(签名固定为 func main()
  • 一个目录下只能有一个 package main,否则 go run . 会报 multiple main packages

用 flag 包读取最简命令行参数

Go 标准库的 flag 包足够应付“最简单”的需求,比如接收一个字符串或整数参数,不需要第三方依赖。

常见错误现象:直接用 os.Args 手动解析,结果漏掉 Args[0] 是程序名,或没处理空参数、类型转换失败等边界情况。

立即学习“go语言免费学习笔记(深入)”;

实操建议:

  • flag.String / flag.Int 声明参数,自动处理默认值、类型转换和帮助信息
  • 必须调用 flag.Parse() 才能触发解析,否则所有 flag.Xxx 返回零值
  • 帮助信息(-h / --help)是内置的,不用额外写逻辑
package main

import (
    "flag"
    "fmt"
)

func main() {
    name := flag.String("name", "World", "your name")
    flag.Parse()
    fmt.Printf("Hello, %s!\n", *name)
}

编译后运行时传参格式要严格

Go 编译出的二进制不支持 ./cmd --name=Tom./cmd --name Tom 混用——flag 包对等号格式敏感,且只认 --xxx-x 形式,不接受 ./cmd Tom 这种无 flag 名的位置参数(除非显式用 flag.Args())。

使用场景:调试阶段常用 go run . --name=Alice;发布时用 go build -o hello && ./hello --name=Bob

容易踩的坑:

  • 忘记空格:--name=Tom ✅,--name= Tom ❌(等号后有空格会导致值为空)
  • 短选项拼接错误:-name Alice ❌(name 不是单字母,不能用短格式),应写 --name Alice
  • 参数顺序:flag 必须在非 flag 参数之前,./hello --name Tom extraextra 会进入 flag.Args(),但 --name 仍能正确解析

没有 main 函数时 go run 会静默失败

如果你删掉了 func main(),或者把它改名叫 func Main()go run . 不会报错,而是直接退出,什么也不输出——这是 Go 工具链的设计:找不到 main 就当“没可运行内容”,而非报错。

这比编译失败更难排查,尤其对新手。验证方式只有两个:

  • 确认文件开头是 package main
  • 确认存在且仅存在一个 func main(),且签名完全匹配(无参数、无返回值)

复杂点在于:如果项目里混了测试文件(xxx_test.go)或工具文件(比如生成代码用的 gen.go),它们也可能声明 package main,导致 go run . 模糊匹配到错误文件。此时应明确指定文件:go run main.go