Skip to content

go flag

go-flag 是 Go 语言标准库中的一个包,用于处理命令行标志和参数。它允许你定义命令行标志(例如 -name--help)并解析命令行输入。flag 包是 Go 语言中用于命令行解析的标准库,使用起来简单直接。

1. 基本使用

flag 包提供了多种标志类型,包括 intstringboolfloat 等等。你可以通过 flag 包定义这些标志,并在程序执行时解析这些标志。

示例:定义和解析命令行标志

go
package main

import (
	"flag"
	"fmt"
)

func main() {
	// 定义标志
	var name = flag.String("name", "User", "The name of the user")
	var age = flag.Int("age", 18, "The age of the user")
	var verbose = flag.Bool("verbose", false, "Enable verbose output")

	// 解析标志
	flag.Parse()

	// 使用标志的值
	fmt.Printf("Name: %s\n", *name)
	fmt.Printf("Age: %d\n", *age)
	if *verbose {
		fmt.Println("Verbose output enabled")
	}
}

在这个例子中:

  • flag.String 用于定义一个字符串类型的标志 --name,默认值为 "User",描述为 "The name of the user"
  • flag.Int 用于定义一个整数类型的标志 --age,默认值为 18,描述为 "The age of the user"
  • flag.Bool 用于定义一个布尔类型的标志 --verbose,默认值为 false,描述为 "Enable verbose output"

当程序运行时,flag.Parse() 会解析命令行输入的标志,之后可以通过指针来访问它们的值。

2. 常用的标志类型

flag 包支持几种常用的标志类型:

  • flag.StringVar:定义字符串标志。
  • flag.IntVar:定义整数标志。
  • flag.BoolVar:定义布尔标志。
  • flag.Float64Var:定义浮动标志。
  • flag.DurationVar:定义时间间隔标志。

示例:使用 StringVarIntVar

go
package main

import (
	"flag"
	"fmt"
)

func main() {
	var name string
	var age int

	// 使用 StringVar 和 IntVar 定义标志
	flag.StringVar(&name, "name", "User", "The name of the user")
	flag.IntVar(&age, "age", 18, "The age of the user")

	// 解析命令行输入
	flag.Parse()

	// 打印解析后的值
	fmt.Printf("Name: %s\n", name)
	fmt.Printf("Age: %d\n", age)
}

3. 解析命令行输入

调用 flag.Parse() 后,标志就会被解析。如果命令行中没有提供某个标志,则使用其默认值。如果有错误的标志或缺少必需的标志,flag 会自动输出错误信息并退出程序。

bash
go run main.go --name="Alice" --age=25

输出:

bash
Name: Alice
Age: 25

4. 使用命令行位置参数

除了标志参数,flag 包还支持位置参数(即标志后面的其他参数)。位置参数可以通过 flag.Args() 获取。

示例:获取位置参数

go
package main

import (
	"flag"
	"fmt"
)

func main() {
	var name string
	flag.StringVar(&name, "name", "User", "The name of the user")

	// 解析标志
	flag.Parse()

	// 打印命令行输入的其他位置参数
	fmt.Printf("Name: %s\n", name)
	fmt.Println("Other args:", flag.Args())
}

命令行输入:

bash
go run main.go --name="Alice" arg1 arg2

输出:

bash
Name: Alice
Other args: [arg1 arg2]

5. 自定义标志类型

flag 包允许你自定义标志类型,只需实现 flag.Value 接口,该接口包含 String()Set(string) 方法。这样你可以创建自己的标志类型来进行特殊处理。

示例:自定义标志类型

go
package main

import (
	"flag"
	"fmt"
	"strconv"
)

// 定义自定义类型
type Age int

// 实现 flag.Value 接口
func (a *Age) String() string {
	return strconv.Itoa(int(*a))
}

func (a *Age) Set(value string) error {
	age, err := strconv.Atoi(value)
	if err != nil {
		return err
	}
	*a = Age(age)
	return nil
}

func main() {
	var age Age
	flag.Var(&age, "age", "The age of the user (custom type)")

	// 解析命令行输入
	flag.Parse()

	// 使用自定义类型的标志
	fmt.Printf("User Age: %d\n", age)
}

命令行输入:

bash
go run main.go --age=30

输出:

bash
User Age: 30

6. 帮助和使用信息

flag 包自动提供帮助功能,用户可以通过 --help-h 来查看程序的使用说明。

bash
go run main.go --help

输出:

bash
Usage of /tmp/go-buildXXXXX/mycli:
  -age int
        The age of the user (custom type)
  -name string
        The name of the user

7. 错误处理

如果命令行中的标志格式不正确或没有提供必需的标志,flag 包会自动输出错误信息并退出程序。你也可以自定义错误处理。

示例:错误处理

go
package main

import (
	"flag"
	"fmt"
)

func main() {
	var age = flag.Int("age", 18, "The age of the user")

	// 如果没有解析标志,就显示帮助信息
	flag.Parse()

	// 如果有错误,可以手动检查
	if *age < 0 {
		fmt.Println("Age must be a positive integer")
		flag.PrintDefaults() // 打印标志的默认信息
	}
}

8. 总结

flag 包是 Go 语言标准库中非常有用的工具,能够简洁地处理命令行标志。它支持:

  • 标准标志类型(如字符串、整数、布尔值等)。
  • 标志解析,自动处理默认值和类型转换。
  • 位置参数和自定义标志类型。
  • 自动生成帮助信息。

适用于简单到中等复杂度的命令行应用程序。如果需要更复杂的功能(例如子命令、动态标志),可以考虑使用像 Cobra 这样的库。