Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

flag - 命令行参数解析

概述

flag 包用于解析命令行参数,支持定义各种类型的标志(flags)。

包导入

import "flag"

基本使用

// 1. 定义标志
verbose := flag.Bool("verbose", false, "启用详细输出")
port := flag.Int("port", 8080, "服务器端口")

// 2. 解析命令行
flag.Parse()

// 3. 访问值
if *verbose {
    fmt.Println("详细模式")
}
fmt.Printf("端口:%d\n", *port)

典型示例

示例 1:完整的 Web 服务器配置

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
    "time"
)

func main() {
    // 定义标志
    port := flag.Int("port", 8080, "HTTP 服务器端口")
    host := flag.String("host", "0.0.0.0", "监听地址")
    timeout := flag.Duration("timeout", 30*time.Second, "读写超时")
    debug := flag.Bool("debug", false, "调试模式")
    
    flag.Parse()
    
    if *debug {
        log.Printf("启动服务器:%s:%d", *host, *port)
    }
    
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello, World!")
    })
    
    server := &http.Server{
        Addr:         fmt.Sprintf("%s:%d", *host, *port),
        ReadTimeout:  *timeout,
        WriteTimeout: *timeout,
    }
    
    log.Fatal(server.ListenAndServe())
}

运行

# 使用默认配置
$ ./webserver

# 自定义端口和超时
$ ./webserver -port 9000 -timeout 1m -debug

示例 2:文件处理工具(多值和自定义类型)

package main

import (
    "flag"
    "fmt"
    "os"
    "strings"
)

// 自定义字符串切片类型
type StringSlice struct {
    values []string
}

func (s *StringSlice) String() string {
    return strings.Join(s.values, ",")
}

func (s *StringSlice) Set(value string) error {
    s.values = append(s.values, value)
    return nil
}

func main() {
    // 定义标志
    var files StringSlice
    verbose := flag.Bool("verbose", false, "详细输出")
    output := flag.String("output", "", "输出文件")
    limit := flag.Int("limit", 100, "最大处理数")
    
    flag.Var(&files, "file", "输入文件(可多次指定)")
    flag.Parse()
    
    // 验证必需参数
    if len(files.values) == 0 {
        fmt.Println("错误:请指定输入文件")
        flag.Usage()
        os.Exit(1)
    }
    
    if *output == "" {
        fmt.Println("错误:请指定输出文件")
        os.Exit(1)
    }
    
    // 处理文件
    if *verbose {
        fmt.Printf("处理 %d 个文件,限制:%d\n", len(files.values), *limit)
        fmt.Printf("输出到:%s\n", *output)
    }
    
    for i, file := range files.values {
        if *verbose {
            fmt.Printf("[%d/%d] 处理:%s\n", i+1, len(files.values), file)
        }
        // 处理文件逻辑...
    }
}

运行

# 处理单个文件
$ ./processor -file input.txt -output result.txt

# 处理多个文件
$ ./processor -file a.txt -file b.txt -file c.txt -output all.txt -verbose

# 带限制处理
$ ./processor -file data.txt -output out.txt -limit 50

一、位置参数访问函数

获取指定索引的位置参数

Arg(i int) string

说明

  • 返回第 i 个位置参数(索引从 0 开始)
  • 索引超出范围返回空字符串

定义/实现

// 内部实现:返回 flag.CommandLine.Arg(i)
func Arg(i int) string {
    return CommandLine.Arg(i)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    flag.Parse()
    
    // 访问第一个参数
    if flag.NArg() > 0 {
        fmt.Printf("第一个参数:%s\n", flag.Arg(0))
    }
    
    // 访问第二个参数
    if flag.NArg() > 1 {
        fmt.Printf("第二个参数:%s\n", flag.Arg(1))
    }
}

运行

$ ./program file1.txt file2.txt
第一个参数:file1.txt
第二个参数:file2.txt

获取所有位置参数

Args() []string

说明

  • 返回所有位置参数(标志解析后剩余的参数)
  • 返回切片,可直接遍历

定义/实现

// 内部实现:返回 flag.CommandLine.Args()
func Args() []string {
    return CommandLine.Args()
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    flag.Parse()
    
    // 获取所有位置参数
    files := flag.Args()
    
    fmt.Printf("参数数量:%d\n", len(files))
    for i, file := range files {
        fmt.Printf("文件 %d: %s\n", i, file)
    }
}

运行

$ ./program -verbose a.txt b.txt c.txt
参数数量:3
文件 0: a.txt
文件 1: b.txt
文件 2: c.txt

获取位置参数数量

NArg() int

说明

  • 返回位置参数的数量
  • 常用于验证是否提供了必需的参数

定义/实现

// 内部实现:返回 flag.CommandLine.NArg()
func NArg() int {
    return CommandLine.NArg()
}

示例

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    flag.Parse()
    
    // 验证必需参数
    if flag.NArg() == 0 {
        fmt.Println("错误:请指定输入文件")
        os.Exit(1)
    }
    
    // 验证参数数量
    if flag.NArg() != 2 {
        fmt.Printf("错误:需要 2 个文件,当前:%d 个\n", flag.NArg())
        os.Exit(1)
    }
    
    fmt.Printf("输入:%s, 输出:%s\n", flag.Arg(0), flag.Arg(1))
}

运行

$ ./program
错误:请指定输入文件

$ ./program in.txt out.txt
输入:in.txt, 输出:out.txt

二、标志定义函数

定义布尔类型标志

*Bool(name string, value bool, usage string) bool

说明

  • 定义 bool 类型标志
  • 返回指向 bool 值的指针
  • 使用:-flag-flag=true/false

定义/实现

// 内部实现:创建 boolValue 并注册
func Bool(name string, value bool, usage string) *bool {
    return CommandLine.Bool(name, value, usage)
}

// boolValue 实现
type boolValue int

func (b *boolValue) Set(s string) error {
    // 解析 true/false/1/0 等
}

func (b *boolValue) String() string {
    return fmt.Sprintf("%v", *b)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细输出")
    debug := flag.Bool("debug", false, "调试模式")
    
    flag.Parse()
    
    if *verbose {
        fmt.Println("详细模式")
    }
    if *debug {
        fmt.Println("调试模式")
    }
    
    fmt.Printf("verbose=%v, debug=%v\n", *verbose, *debug)
}

运行

$ ./program -verbose
详细模式
verbose=true, debug=false

$ ./program -verbose=false -debug
调试模式
verbose=false, debug=true

定义时间间隔类型标志

*Duration(name string, value time.Duration, usage string) time.Duration

说明

  • 定义 time.Duration 类型标志
  • 支持格式:30s2m1h1h30m20s500ms

定义/实现

// 内部实现:使用 time.ParseDuration 解析
func Duration(name string, value time.Duration, usage string) *time.Duration {
    return CommandLine.Duration(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
    "time"
)

func main() {
    timeout := flag.Duration("timeout", 30*time.Second, "超时时间")
    interval := flag.Duration("interval", 5*time.Minute, "间隔")
    
    flag.Parse()
    
    fmt.Printf("超时:%v\n", *timeout)
    fmt.Printf("间隔:%v\n", *interval)
    
    // 使用
    time.Sleep(*timeout)
    
    // 转换单位
    fmt.Printf("超时 (ms): %d\n", timeout.Milliseconds())
}

运行

$ ./program -timeout 1m -interval 2h
超时:1m0s
间隔:2h0m0s
超时 (ms): 60000

定义浮点数类型标志

*Float64(name string, value float64, usage string) float64

说明

  • 定义 float64 类型标志
  • 支持科学计数法:1.5e10

定义/实现

func Float64(name string, value float64, usage string) *float64 {
    return CommandLine.Float64(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    ratio := flag.Float64("ratio", 0.5, "比例")
    price := flag.Float64("price", 99.99, "价格")
    
    flag.Parse()
    
    fmt.Printf("比例:%.2f\n", *ratio)
    fmt.Printf("价格:%.2f\n", *price)
    
    // 验证
    if *ratio < 0.0 || *ratio > 1.0 {
        fmt.Println("比例必须在 0-1 之间")
    }
}

运行

$ ./program -ratio 0.75 -price 199.99
比例:0.75
价格:199.99

定义函数类型标志

Func(name string, usage string, fn func(string) error)

说明

  • 定义函数类型标志
  • 每次指定标志时都会调用函数
  • 适合收集多个值或执行操作

定义/实现

func Func(name string, usage string, fn func(string) error) {
    CommandLine.Func(name, usage, fn)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    var commands []string
    
    flag.Func("exec", "执行命令", func(s string) error {
        commands = append(commands, s)
        fmt.Printf("添加:%s\n", s)
        return nil
    })
    
    flag.Parse()
    
    fmt.Printf("所有命令:%v\n", commands)
}

运行

$ ./program -exec "ls" -exec "pwd" -exec "date"
添加:ls
添加:pwd
添加:date
所有命令:[ls pwd date]

定义整数类型标志

*Int(name string, value int, usage string) int

说明

  • 定义 int 类型标志
  • 返回指向 int 值的指针

定义/实现

func Int(name string, value int, usage string) *int {
    return CommandLine.Int(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    port := flag.Int("port", 8080, "端口")
    count := flag.Int("count", 10, "数量")
    
    flag.Parse()
    
    fmt.Printf("端口:%d\n", *port)
    fmt.Printf("数量:%d\n", *count)
    
    // 验证
    if *port < 1 || *port > 65535 {
        fmt.Println("端口无效")
    }
}

运行

$ ./program -port 9000 -count 100
端口:9000
数量:100

定义 64 位整数类型标志

*Int64(name string, value int64, usage string) int64

说明

  • 定义 int64 类型标志
  • 用于大整数

定义/实现

func Int64(name string, value int64, usage string) *int64 {
    return CommandLine.Int64(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    maxSize := flag.Int64("max-size", 1024*1024*1024, "最大大小 (字节)")
    
    flag.Parse()
    
    fmt.Printf("最大大小:%d 字节 (%.2f GB)\n", 
        *maxSize, float64(*maxSize)/1024/1024/1024)
}

运行

$ ./program -max-size 5368709120
最大大小:5368709120 字节 (5.00 GB)

定义字符串类型标志

*String(name string, value string, usage string) string

说明

  • 定义 string 类型标志
  • 返回指向 string 值的指针

定义/实现

func String(name string, value string, usage string) *string {
    return CommandLine.String(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    host := flag.String("host", "localhost", "主机")
    output := flag.String("output", "", "输出文件 (必需)")
    
    flag.Parse()
    
    // 验证必需参数
    if *output == "" {
        fmt.Println("错误:必须指定输出文件")
        os.Exit(1)
    }
    
    fmt.Printf("主机:%s, 输出:%s\n", *host, *output)
}

运行

$ ./program -host example.com -output result.txt
主机:example.com, 输出:result.txt

定义文本解析类型标志

TextVar(value encoding.TextUnmarshaler, name string, value string, usage string)

说明

  • 定义实现 encoding.TextUnmarshaler 接口的标志
  • 自动处理文本解析(如 net.IP、url.URL)

定义/实现

func TextVar(value encoding.TextUnmarshaler, name string, val string, usage string) {
    CommandLine.TextVar(value, name, val, usage)
}

示例

package main

import (
    "flag"
    "fmt"
    "net"
)

func main() {
    var ip net.IP
    flag.TextVar(&ip, "ip", "127.0.0.1", "IP 地址")
    
    flag.Parse()
    
    fmt.Printf("IP: %v\n", ip)
}

运行

$ ./program -ip 192.168.1.1
IP: 192.168.1.1

定义无符号整数类型标志

*Uint(name string, value uint, usage string) uint

说明

  • 定义 uint 类型标志
  • 用于非负整数

定义/实现

func Uint(name string, value uint, usage string) *uint {
    return CommandLine.Uint(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    limit := flag.Uint("limit", 100, "限制")
    
    flag.Parse()
    
    fmt.Printf("限制:%d\n", *limit)
    
    if *limit == 0 {
        fmt.Println("限制不能为 0")
    }
}

定义 64 位无符号整数类型标志

*Uint64(name string, value uint64, usage string) uint64

说明

  • 定义 uint64 类型标志
  • 用于大非负整数

定义/实现

func Uint64(name string, value uint64, usage string) *uint64 {
    return CommandLine.Uint64(name, value, usage)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    maxMem := flag.Uint64("max-memory", 1024*1024*1024, "最大内存 (字节)")
    
    flag.Parse()
    
    fmt.Printf("最大内存:%d MB\n", *maxMem/1024/1024)
}

定义自定义类型标志

Var(value Value, name string, usage string)

说明

  • 定义自定义类型标志
  • value 必须实现 Value 接口(String() 和 Set(string) 方法)

定义/实现

func Var(value Value, name string, usage string) {
    CommandLine.Var(value, name, usage)
}

// Value 接口
type Value interface {
    String() string
    Set(string) error
}

示例 1:字符串切片

package main

import (
    "flag"
    "fmt"
    "strings"
)

type StringSlice struct {
    values []string
}

func (s *StringSlice) String() string {
    return strings.Join(s.values, ",")
}

func (s *StringSlice) Set(value string) error {
    s.values = append(s.values, value)
    return nil
}

func main() {
    var files StringSlice
    flag.Var(&files, "file", "文件列表")
    
    flag.Parse()
    
    fmt.Printf("文件:%v\n", files.values)
}

运行

$ ./program -file a.txt -file b.txt -file c.txt
文件:[a.txt b.txt c.txt]

示例 2:带验证的端口

type PortValue struct {
    port int
}

func (p *PortValue) String() string {
    return fmt.Sprintf("%d", p.port)
}

func (p *PortValue) Set(value string) error {
    port, err := strconv.Atoi(value)
    if err != nil {
        return err
    }
    if port < 1 || port > 65535 {
        return fmt.Errorf("端口必须在 1-65535 之间")
    }
    p.port = port
    return nil
}

// 使用
var port PortValue
port.port = 8080
flag.Var(&port, "port", "端口")

三、标志解析函数

解析命令行参数

Parse()

说明

  • 解析 CommandLine 的标志
  • 必须在访问标志值之前调用

定义/实现

func Parse() {
    CommandLine.Parse(os.Args[1:])
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    port := flag.Int("port", 8080, "端口")
    
    // 必须先解析
    flag.Parse()
    
    // 然后访问
    if *verbose {
        fmt.Println("详细模式")
    }
    fmt.Printf("端口:%d\n", *port)
    
    // 访问位置参数
    fmt.Printf("参数:%v\n", flag.Args())
}

运行

$ ./program -verbose -port 9000 file1.txt
详细模式
端口:9000
参数:[file1.txt]

检查是否已解析

Parsed() bool

说明

  • 检查是否已调用 Parse()

定义/实现

func Parsed() bool {
    return CommandLine.Parsed()
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    
    if !flag.Parsed() {
        fmt.Println("尚未解析")
        flag.Parse()
    }
    
    fmt.Printf("Verbose: %v\n", *verbose)
}

手动设置标志值

Set(name, value string) error

说明

  • 手动设置标志值
  • 必须在 Parse() 之前调用

定义/实现

func Set(name, value string) error {
    return CommandLine.Set(name, value)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    port := flag.Int("port", 8080, "端口")
    
    // 解析前手动设置
    flag.Set("port", "9090")
    
    flag.Parse()
    
    fmt.Printf("端口:%d\n", *port)  // 9090
}

更改默认值

ChangeDefault(name string, value interface{}) error

说明

  • 更改标志的默认值
  • 只影响帮助信息中的默认值显示

定义/实现

func ChangeDefault(name string, value interface{}) error {
    return CommandLine.ChangeDefault(name, value)
}

示例

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    port := flag.Int("port", 8080, "端口")
    
    // 从环境变量获取默认值
    if envPort := os.Getenv("PORT"); envPort != "" {
        flag.ChangeDefault("port", envPort)
    }
    
    flag.Parse()
    
    fmt.Printf("端口:%d\n", *port)
}

运行

$ export PORT=9090
$ ./program
端口:9090

四、标志访问函数

查找标志

*Lookup(name string) Flag

说明

  • 查找指定名称的标志
  • 不存在返回 nil

定义/实现

func Lookup(name string) *Flag {
    return CommandLine.Lookup(name)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    flag.Parse()
    
    // 查找标志
    f := flag.Lookup("verbose")
    if f != nil {
        fmt.Printf("名称:%s\n", f.Name)
        fmt.Printf("说明:%s\n", f.Usage)
        fmt.Printf("值:%s\n", f.Value)
        fmt.Printf("默认值:%s\n", f.DefValue)
    }
}

获取已设置标志数量

NFlag() int

说明

  • 返回命令行中显式指定的标志数量
  • 不包括使用默认值的标志

定义/实现

func NFlag() int {
    return CommandLine.NFlag()
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    port := flag.Int("port", 8080, "端口")
    
    flag.Parse()
    
    fmt.Printf("设置了 %d 个标志\n", flag.NFlag())
}

运行

$ ./program -verbose
设置了 1 个标志

遍历已设置的标志

*Visit(fn func(Flag))

说明

  • 只遍历命令行中显式指定的标志
  • 不包括使用默认值的标志

定义/实现

func Visit(fn func(*Flag)) {
    CommandLine.Visit(fn)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    port := flag.Int("port", 8080, "端口")
    
    flag.Parse()
    
    // 只遍历设置的标志
    flag.Visit(func(f *flag.Flag) {
        fmt.Printf("%s = %s\n", f.Name, f.Value)
    })
}

运行

$ ./program -verbose
verbose = true

遍历所有标志

*VisitAll(fn func(Flag))

说明

  • 遍历所有标志(包括未设置的)
  • 按字母顺序

定义/实现

func VisitAll(fn func(*Flag)) {
    CommandLine.VisitAll(fn)
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    port := flag.Int("port", 8080, "端口")
    
    flag.Parse()
    
    // 遍历所有标志
    flag.VisitAll(func(f *flag.Flag) {
        fmt.Printf("%s = %s (默认:%s)\n", 
            f.Name, f.Value, f.DefValue)
    })
}

运行

$ ./program -verbose
host = localhost (默认:localhost)
port = 8080 (默认:8080)
verbose = true (默认:false)

五、输出和帮助函数

打印所有标志的默认值

PrintDefaults()

说明

  • 打印所有标志及使用说明
  • 按字母顺序排列

定义/实现

func PrintDefaults() {
    CommandLine.PrintDefaults()
}

示例

package main

import (
    "flag"
    "fmt"
)

func main() {
    verbose := flag.Bool("verbose", false, "详细")
    port := flag.Int("port", 8080, "端口")
    
    flag.Parse()
    
    fmt.Println("使用说明:")
    flag.PrintDefaults()
}

运行

$ ./program
使用说明:
  -port int
        端口 (default 8080)
  -verbose
        详细

设置输出目的地

SetOutput(output io.Writer)

说明

  • 设置错误和使用信息的输出
  • 默认是 os.Stderr

定义/实现

func SetOutput(output io.Writer) {
    CommandLine.SetOutput(output)
}

示例

package main

import (
    "flag"
    "os"
)

func main() {
    // 输出到文件
    file, _ := os.Create("errors.log")
    flag.SetOutput(file)
    defer file.Close()
    
    flag.Parse()
}

设置用法函数

SetUsage(usage func())

说明

  • 设置自定义的使用信息函数
  • 解析错误时自动调用

定义/实现

func SetUsage(usage func()) {
    CommandLine.SetUsage(usage)
}

示例

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    flag.SetUsage(func() {
        fmt.Fprintf(os.Stderr, "用法:%s [选项] [文件...]\n", os.Args[0])
        flag.PrintDefaults()
    })
    
    flag.Parse()
    
    if flag.NArg() == 0 {
        fmt.Fprintf(os.Stderr, "错误:请指定文件\n\n")
        flag.Usage()
        os.Exit(1)
    }
}

调用用法函数

Usage()

说明

  • 调用使用信息函数
  • 解析错误时自动调用,也可手动调用

定义/实现

var Usage = func() {
    fmt.Fprintf(CommandLine.Output(), "usage: %s [options]\n", os.Args[0])
    PrintDefaults()
}

示例

package main

import (
    "flag"
    "os"
)

func main() {
    help := flag.Bool("help", false, "显示帮助")
    
    flag.Parse()
    
    if *help {
        flag.Usage()
        os.Exit(0)
    }
}

运行

$ ./program -help
usage: ./program [options]
  -help
        显示帮助

六、FlagSet 管理函数

创建新的标志集合

*NewFlagSet(name string, errorHandling ErrorHandling) FlagSet

说明

  • 创建独立的 FlagSet
  • 适合实现子命令

定义/实现

func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
    f := &FlagSet{}
    f.Init(name, errorHandling)
    return f
}

示例:子命令

package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    if len(os.Args) < 2 {
        fmt.Println("请指定子命令")
        os.Exit(1)
    }
    
    switch os.Args[1] {
    case "add":
        addCmd := flag.NewFlagSet("add", flag.ExitOnError)
        name := addCmd.String("name", "", "名称")
        addCmd.Parse(os.Args[2:])
        fmt.Printf("添加:%s\n", *name)
        
    case "delete":
        delCmd := flag.NewFlagSet("delete", flag.ExitOnError)
        id := delCmd.Int("id", 0, "ID")
        delCmd.Parse(os.Args[2:])
        fmt.Printf("删除 ID: %d\n", *id)
    }
}

运行

$ ./program add -name Alice
添加:Alice

$ ./program delete -id 123
删除 ID: 123

七、核心类型

标志结构体

Flag

定义

type Flag struct {
    Name     string // 标志名称
    Usage    string // 使用说明
    Value    Value  // 值对象
    DefValue string // 默认值字符串
}

示例

// 通过 Lookup 获取 Flag
f := flag.Lookup("verbose")
if f != nil {
    fmt.Printf("名称:%s\n", f.Name)
    fmt.Printf("说明:%s\n", f.Usage)
    fmt.Printf("值:%s\n", f.Value)
    fmt.Printf("默认值:%s\n", f.DefValue)
}

标志集合结构体

FlagSet

定义

type FlagSet struct {
    // 内部字段
}

主要方法

// 创建
fs := flag.NewFlagSet("name", flag.ContinueOnError)

// 定义标志
fs.Bool("v", false, "详细")
fs.Int("p", 8080, "端口")

// 解析
err := fs.Parse(os.Args[1:])

// 访问
fs.Args()
fs.NArg()
fs.Lookup("v")
fs.Visit(fn)
fs.VisitAll(fn)

// 输出
fs.PrintDefaults()
fs.SetOutput(w)
fs.SetUsage(fn)

标志值接口

Value

定义

type Value interface {
    String() string
    Set(string) error
}

示例:自定义类型

type SliceValue struct {
    slice []string
}

func (s *SliceValue) String() string {
    return strings.Join(s.slice, ",")
}

func (s *SliceValue) Set(value string) error {
    s.slice = append(s.slice, value)
    return nil
}

// 使用
var files SliceValue
flag.Var(&files, "file", "文件")

错误处理策略类型

ErrorHandling

定义

type ErrorHandling int

const (
    ContinueOnError ErrorHandling = iota // 返回错误
    ExitOnError                          // 调用 os.Exit(2)
    PanicOnError                         // 调用 panic
)

示例

// ContinueOnError - 返回错误
fs := flag.NewFlagSet("test", flag.ContinueOnError)
err := fs.Parse(args)
if err != nil {
    // 处理错误
}

// ExitOnError - 自动退出(默认)
fs := flag.NewFlagSet("test", flag.ExitOnError)
fs.Parse(args)  // 错误时自动退出

// PanicOnError - panic
fs := flag.NewFlagSet("test", flag.PanicOnError)
fs.Parse(args)  // 错误时 panic

八、包级别变量

默认标志集合

CommandLine

定义

var CommandLine = NewFlagSet(os.Args[0], ExitOnError)

说明

  • 包级别的默认 FlagSet
  • 所有包级别函数都操作此 FlagSet

示例

// 使用包级别函数(推荐)
verbose := flag.Bool("verbose", false, "详细")
flag.Parse()

// 或显式使用
verbose := flag.CommandLine.Bool("verbose", false, "详细")
flag.CommandLine.Parse(os.Args[1:])

默认输出目的地

Output

定义

var Output io.Writer = os.Stderr

说明

  • 默认错误和使用信息输出到 os.Stderr
  • 可以修改

示例

// 修改输出
file, _ := os.Create("errors.log")
flag.Output = file

默认用法函数

Usage

定义

var Usage = func() {
    fmt.Fprintf(CommandLine.Output(), "usage: %s [options]\n", os.Args[0])
    PrintDefaults()
}

说明

  • 默认的使用信息函数
  • 可以自定义

示例

flag.Usage = func() {
    fmt.Fprintf(os.Stderr, "我的程序\n")
    fmt.Fprintf(os.Stderr, "用法:%s [选项]\n\n", os.Args[0])
    flag.PrintDefaults()
}

快速参考

标志定义

函数类型示例
Boolboolflag.Bool("v", false, "详细")
Intintflag.Int("port", 8080, "端口")
Int64int64flag.Int64("max", 1000, "最大")
Uintuintflag.Uint("limit", 100, "限制")
Uint64uint64flag.Uint64("size", 0, "大小")
Float64float64flag.Float64("ratio", 0.5, "比例")
Stringstringflag.String("host", "localhost", "主机")
Durationtime.Durationflag.Duration("timeout", 30*time.Second, "超时")
VarValueflag.Var(&slice, "file", "文件")
TextVarTextUnmarshalerflag.TextVar(&ip, "ip", "127.0.0.1", "IP")
Funcfunc(string) errorflag.Func("exec", "执行", fn)

解析和访问

函数说明
Parse()解析命令行
Parsed()检查是否已解析
Args()获取位置参数
Arg(i)获取第 i 个参数
NArg()参数数量
NFlag()标志数量
Lookup(name)查找标志
Visit(fn)遍历已设置的标志
VisitAll(fn)遍历所有标志

输出

函数说明
PrintDefaults()打印帮助
SetOutput(w)设置输出
SetUsage(fn)设置用法函数
Usage()调用用法

最后更新:2026-04-03
Go 版本:Go 1.23+