Skip to content

Cobra Flag 分组完全指南:打造像 Docker 一样专业的 CLI 帮助信息

Cobra Flag 分组帮助信息效果预览示意图

引言

在开发 CLI 工具时,--help 是用户接触最多的功能之一。良好的帮助信息能显著提升工具的易用性和专业性。然而,在使用 Go 的 Cobra 框架时,默认的帮助输出将所有 flags 混在一起,随着功能的增加,flags 数量激增,可读性急剧下降。

本文将通过一个实战案例,介绍如何为 Cobra 命令实现自定义的 Flag 分组显示,让帮助信息像 dockerkubectl 等专业 CLI 工具一样清晰有序。

为什么不直接修改 UsageTemplate?

在开始之前,先回答一个常见问题:Cobra 不是提供了 SetUsageTemplate() 方法吗?为什么不直接用?

go
cmd.SetUsageTemplate(`{{.UseLine}} ...`)

SetUsageTemplate 的局限性:

问题说明
模板字符串调试困难需要熟悉 Go 模板语法,错误提示不友好
无法灵活控制分组逻辑模板中只能按全局顺序输出所有 flags,无法按分组渲染
难以复用每个命令都要写一遍模板,维护成本高

而本文采用的 Annotations + 自定义 HelpFunc 方案,用代码控制输出逻辑,更加灵活可控,且可以在多个命令间复用。

效果预览

先来看看我们最终要实现的效果:

bash
$ agentctl mkdir --help
Create directory for finalfs filesystem

Usage:
  agentctl mkdir [flags]

Examples:
  # Create a directory with default settings
  agentctl mkdir --path /data/new_folder

  # Create with specific permissions and ownership
  agentctl mkdir --path /data/project --access_mode 0750 --uid 1001 --gid 1001

  # Create with case-insensitive support
  agentctl mkdir --path /data/shared --casefold --prefer_mds "mds1,mds2"

Target:
  --path                  Target directory path to create (default: /data/shared)
  --use_absolute_path     Treat the provided path as an absolute path (default: false)

Permission & Ownership:
  --access_mode           Directory access permissions in octal format (e.g., 0755) (default: 0755)
  --uid                   User ID (UID) for the directory owner (default: 0)
  --gid                   Group ID (GID) for the directory group owner (default: 0)

Metadata & Advanced:
  --prefer_mds            Comma-separated list of preferred MDS IDs or group IDs for metadata location
  --not_use_mirror        Disable mirroring for this directory (default: false)
  --casefold              Enable case-insensitive folder (casefolding) for the directory (default: false)

Global Flags:
  -h, --help   help for mkdir

可以看到,flags 按照功能被分为了 "Target"、"Permission & Ownership"、"Metadata & Advanced" 三个逻辑组,一目了然。

核心实现:FlagsHelper

首先,我们需要设计一个通用的辅助组件 FlagsHelper,它负责按分组打印 flags。为了保持灵活性,我们采用 Functional Options 模式来配置。

数据结构设计

go
package flagshelper

import (
	"fmt"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

type FlagsHelper struct {
	spacing int  // flag 名称与描述之间的最小间距
}

spacing 控制着 flag 名称和描述之间的对齐间距,让输出更加整齐美观。

Functional Options 模式

go
type Option func(flagshelper *FlagsHelper)

func WithSpacing(spacing int) Option {
	return func(flagshelper *FlagsHelper) {
		flagshelper.spacing = spacing
	}
}

func NewFlagsHelper(options ...Option) *FlagsHelper {
	f := &FlagsHelper{spacing: 20}  // 默认间距 20
	for _, ops := range options {
		ops(f)
	}
	return f
}

这种设计模式的优势在于:

  • 可扩展性好:未来可以轻松添加新的配置选项
  • API 友好:调用者只需关注自己需要的配置
  • 默认值优雅:提供合理的默认值,大部分场景无需额外配置

核心打印函数

PrintFlagGroupFlagsHelper 的核心方法,它接收命令和分组名称,打印该分组下的所有 flags。

go
func (f *FlagsHelper) PrintFlagGroup(cmd *cobra.Command, groupName string) {
	fmt.Fprintf(cmd.OutOrStdout(), "\n%s:\n", groupName)
	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
		if groups, ok := flag.Annotations["group"]; ok {
			for _, g := range groups {
				if g == groupName {
					// 构建默认值显示部分
					defaultStr := ""
					if flag.DefValue != "" && flag.DefValue != "[]" {
						defaultStr = fmt.Sprintf(" (default: %v)", flag.DefValue)
					}

					// 计算对齐间距(保持至少2个空格的间隔)
					flagName := "--" + flag.Name
					spacing := f.spacing - len(flagName)
					if spacing < 2 {
						spacing = 2
					}

					// 输出格式化后的flag信息
					fmt.Fprintf(cmd.OutOrStdout(), "  %-*s%s%s\n",
						len(flagName)+spacing,
						flagName,
						flag.Usage,
						defaultStr)
				}
			}
		}
	})
}

关键点解析:

  1. 通过 Annotations 识别分组:使用 flag.Annotations["group"] 获取 flag 所属的分组列表
  2. 动态计算对齐:根据 flag 名称长度动态计算空格数,保证所有描述对齐
  3. 智能显示默认值:空数组和空字符串不显示默认值,避免冗余
  4. 最小间距保护:即使 flag 名称很长,也至少保留 2 个空格

关于 Annotations 的原理

Cobra 底层使用的是 github.com/spf13/pflag 包,每个 Flag 结构体包含一个 Annotations 字段,类型为 map[string][]string

go
// pflag 包中的 Flag 结构体
type Flag struct {
    Name        string
    Usage       string
    DefValue    string
    Annotations map[string][]string  // 我们用来存储分组信息
    // ...
}

当我们调用 SetAnnotation("path", "group", []string{"Target"}) 时,实际上是在这个 map 中写入了一条记录:

go
flag.Annotations["group"] = []string{"Target"}

PrintFlagGroup 中,我们通过读取 flag.Annotations["group"] 来判断这个 flag 属于哪个分组。这种设计使得我们可以为 flag 附加任意元数据,而无需修改 flag 的结构定义。

扩展性:你甚至可以定义其他 Annotation 键名,例如 "deprecated""experimental",然后在 HelpFunc 中做特殊渲染。

实战应用:mkdir 命令

现在我们将 FlagsHelper 应用到具体的命令实现中。

定义分组常量

首先定义分组名称常量,便于统一管理:

go
const (
	targetGroup     = "Target"
	permissionGroup = "Permission & Ownership"
	metadataGroup   = "Metadata & Advanced"
)

定义命令变量

go
var (
	// path specifies the target directory path to be created
	path string

	// useAbsolutePath determines whether the provided path should be treated as an absolute path
	// Default: false (relative path)
	useAbsolutePath bool

	// preferMds specifies preferred MDS (Metadata Server) for locating metadata
	// Can be MDS ID or group ID, separated by commas (e.g., "mds1,mds2" or "group1,group2")
	// If empty, system will automatically select the appropriate MDS
	preferMds string

	// accessMode defines the directory permissions in octal format
	// Default: "0755" (rwxr-xr-x)
	accessMode string

	// uid specifies the User ID (UID) for the directory owner
	// Default: 0 (root user)
	uid uint64

	// gid specifies the Group ID (GID) for the directory group owner
	// Default: 0 (root group)
	gid uint64

	// notUseMirror disables mirroring for the directory when set to true
	// Default: false (mirroring enabled)
	notUseMirror bool

	// casefold enables case-insensitive folder (casefolding) support
	// If not set, inherits the parent directory's casefold strategy
	// Default: false (case-sensitive)
	casefold bool
)

每个变量都带有清晰的注释,说明其用途和默认值,这在代码维护时非常有价值。

配置 Flags 并添加分组

go
func (d *mkdir) setFlags() {
	// 禁用自动排序以保持添加顺序
	d.command.Flags().SortFlags = false

	// ===== Target 分组 =====
	d.command.Flags().String("path", "/data/shared", "Target directory path to create")
	d.command.Flags().SetAnnotation("path", "group", []string{targetGroup})

	d.command.Flags().Bool("use_absolute_path", false, "Treat the provided path as an absolute path")
	d.command.Flags().SetAnnotation("use_absolute_path", "group", []string{targetGroup})

	// ===== Permission & Ownership 分组 =====
	d.command.Flags().String("access_mode", "0755", "Directory access permissions in octal format (e.g., 0755)")
	d.command.Flags().SetAnnotation("access_mode", "group", []string{permissionGroup})

	d.command.Flags().Uint64("uid", 0, "User ID (UID) for the directory owner")
	d.command.Flags().SetAnnotation("uid", "group", []string{permissionGroup})

	d.command.Flags().Uint64("gid", 0, "Group ID (GID) for the directory group owner")
	d.command.Flags().SetAnnotation("gid", "group", []string{permissionGroup})

	// ===== Metadata & Advanced 分组 =====
	d.command.Flags().String("prefer_mds", "", "Comma-separated list of preferred MDS IDs or group IDs for metadata location")
	d.command.Flags().SetAnnotation("prefer_mds", "group", []string{metadataGroup})

	d.command.Flags().Bool("not_use_mirror", false, "Disable mirroring for this directory")
	d.command.Flags().SetAnnotation("not_use_mirror", "group", []string{metadataGroup})

	d.command.Flags().Bool("casefold", false, "Enable case-insensitive folder (casefolding) for the directory")
	d.command.Flags().SetAnnotation("casefold", "group", []string{metadataGroup})

	// ... HelpFunc 配置 ...
}

每个 flag 通过 SetAnnotation 方法绑定到对应的分组。注意 SortFlags = false 可以保持 flags 的添加顺序,让相关 flags 在组内有序排列。

一个 flag 属于多个分组SetAnnotation 的第三个参数是 []string,这意味着一个 flag 可以属于多个分组。虽然实际场景中通常只归属一个分组,但这种设计为未来提供了灵活性。

自定义 HelpFunc

HelpFunc 是 Cobra 提供的扩展点,我们可以完全控制帮助信息的输出格式:

go
func (d *mkdir) setFlags() {
	// ... flags 配置 ...

	var flaghelper = flagshelper.NewFlagsHelper(flagshelper.WithSpacing(24))
	d.command.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		// 基础帮助信息
		fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n", d.command.Short)
		fmt.Fprintf(cmd.OutOrStdout(), "Usage:\n  %s [flags]\n\n", cmd.CommandPath())

		// 显示使用示例
		if d.command.Example != "" {
			fmt.Fprintf(cmd.OutOrStdout(), "Examples:\n%s\n\n", d.command.Example)
		}

		// 分组显示 flags
		flaghelper.PrintFlagGroup(cmd, targetGroup)
		flaghelper.PrintFlagGroup(cmd, permissionGroup)
		flaghelper.PrintFlagGroup(cmd, metadataGroup)

		// 显示全局帮助 flag
		fmt.Fprintf(cmd.OutOrStdout(), "\nGlobal Flags:\n  -h, --help   help for %s\n", cmd.Name())
	})
}

在自定义 HelpFunc 中,我们保留了标准的 Short 描述和 Usage,然后依次添加了 Examples 和分组 flags。

Example 字段

Cobra 的 Command 结构体提供了 Example 字段,用于存储命令使用示例:

go
Example: `# Create a directory with default settings
agentctl mkdir --path /data/new_folder

# Create with specific permissions and ownership
agentctl mkdir --path /data/project --access_mode 0750 --uid 1001 --gid 1001

# Create with case-insensitive support
agentctl mkdir --path /data/shared --casefold --prefer_mds "mds1,mds2"`,

💡 注意

Example 字段默认不会自动显示,需要在自定义 HelpFunc 中手动输出。

完整命令实现

将以上所有部分组合起来,得到完整的命令实现:

go
package mkdir

import (
	"context"
	"embed"
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/fishfinal/cobra-flag-group-example/cmd/agentctl/commander"
	"github.com/fishfinal/cobra-flag-group-example/cmd/agentctl/helper/flagshelper"
	"github.com/fishfinal/cobra-flag-group-example/internal/client"
	"github.com/fishfinal/cobra-flag-group-example/internal/gen/agent"

	"github.com/logrusorgru/aurora"
	"github.com/shaichunfeng/gologger"
	"github.com/spf13/cobra"
)

type Commander interface {
	commander.Commander
}

func NewCommander(clientGetter func() client.AgentClient, embeds embed.FS, aurora aurora.Aurora) Commander {
	return &mkdir{
		clientGetter: clientGetter,
		embeds:       embeds,
		aurora:       aurora,
	}
}

type mkdir struct {
	clientGetter func() client.AgentClient
	embeds       embed.FS
	aurora       aurora.Aurora
	command      *cobra.Command
}

func (d *mkdir) Command() *cobra.Command {
	d.command = d.getCommand()
	d.setFlags()
	return d.command
}

var err error

var (
	// path specifies the target directory path to be created
	path string

	// useAbsolutePath determines whether the provided path should be treated as an absolute path
	// Default: false (relative path)
	useAbsolutePath bool

	// preferMds specifies preferred MDS (Metadata Server) for locating metadata
	// Can be MDS ID or group ID, separated by commas (e.g., "mds1,mds2" or "group1,group2")
	// If empty, system will automatically select the appropriate MDS
	preferMds string

	// accessMode defines the directory permissions in octal format
	// Default: "0755" (rwxr-xr-x)
	accessMode string

	// uid specifies the User ID (UID) for the directory owner
	// Default: 0 (root user)
	uid uint64

	// gid specifies the Group ID (GID) for the directory group owner
	// Default: 0 (root group)
	gid uint64

	// notUseMirror disables mirroring for the directory when set to true
	// Default: false (mirroring enabled)
	notUseMirror bool

	// casefold enables case-insensitive folder (casefolding) support
	// If not set, inherits the parent directory's casefold strategy
	// Default: false (case-sensitive)
	casefold bool
)

func (d *mkdir) getCommand() *cobra.Command {
	return &cobra.Command{
		Use:   "mkdir",
		Short: "Create directory for finalfs filesystem",
		Example: `  # Create a directory with default settings
  agentctl mkdir --path /data/new_folder

  # Create with specific permissions and ownership
  agentctl mkdir --path /data/project --access_mode 0750 --uid 1001 --gid 1001

  # Create with case-insensitive support
  agentctl mkdir --path /data/shared --casefold --prefer_mds "mds1,mds2"`,

		PreRunE: func(cmd *cobra.Command, args []string) error {
			path, err = cmd.Flags().GetString("path")
			if err != nil {
				return fmt.Errorf("failed to get the path option")
			}

			useAbsolutePath, err = cmd.Flags().GetBool("use_absolute_path")
			if err != nil {
				return fmt.Errorf("failed to get the use_absolute_path option")
			}

			preferMds, err = cmd.Flags().GetString("prefer_mds")
			if err != nil {
				return fmt.Errorf("failed to get the prefer_mds option")
			}

			accessMode, err = cmd.Flags().GetString("access_mode")
			if err != nil {
				return fmt.Errorf("failed to get the access_mode option")
			}

			uid, err = cmd.Flags().GetUint64("uid")
			if err != nil {
				return fmt.Errorf("failed to get the uid option")
			}

			gid, err = cmd.Flags().GetUint64("gid")
			if err != nil {
				return fmt.Errorf("failed to get the gid option")
			}

			notUseMirror, err = cmd.Flags().GetBool("not_use_mirror")
			if err != nil {
				return fmt.Errorf("failed to get the not_use_mirror option")
			}

			casefold, err = cmd.Flags().GetBool("casefold")
			if err != nil {
				return fmt.Errorf("failed to get the casefold option")
			}
			return nil
		},
		Run: func(cmd *cobra.Command, args []string) {
			str := gologger.Info().Str("path", path)
			str = str.Str("use_absolute_path", strconv.FormatBool(useAbsolutePath))
			str.Msg(d.aurora.Green("Received params").String())

			clientGetter := d.clientGetter()
			if clientGetter == nil {
				gologger.Error().Msg("yrfs agent client not initialized, please check config")
				return
			}

			ctx := cmd.Context()
			if ctx == nil {
				ctx = context.Background()
			}

			response, err := clientGetter.MkdirClient().MkDir(ctx, &agent.MkDirRequest{
				UseAbsolutePath: useAbsolutePath,
				Path:            path,
				PreferMds:       preferMds,
				AccessMode:      accessMode,
				Uid:             uid,
				Gid:             gid,
				NotUseMirror:    notUseMirror,
				Casefold:        casefold,
			})
			if err != nil {
				gologger.Error().Str("error", err.Error()).Msg("Failed to get the target option")
				return
			}

			rawData, err := json.MarshalIndent(response, "", "  ")
			if err != nil {
				gologger.Error().Str("error", err.Error()).Msg("Failed to JSON marshal")
				return
			}
			fmt.Printf("%s\n", string(rawData))
		},
	}
}

const (
	// 定义分组常量
	targetGroup     = "Target"
	permissionGroup = "Permission & Ownership"
	metadataGroup   = "Metadata & Advanced"
)

func (d *mkdir) setFlags() {
	// 禁用自动排序以保持添加顺序
	d.command.Flags().SortFlags = false

	// ===== Target 分组 =====
	d.command.Flags().String("path", "/data/shared", "Target directory path to create")
	d.command.Flags().SetAnnotation("path", "group", []string{targetGroup})

	d.command.Flags().Bool("use_absolute_path", false, "Treat the provided path as an absolute path")
	d.command.Flags().SetAnnotation("use_absolute_path", "group", []string{targetGroup})

	// ===== Permission & Ownership 分组 =====
	d.command.Flags().String("access_mode", "0755", "Directory access permissions in octal format (e.g., 0755)")
	d.command.Flags().SetAnnotation("access_mode", "group", []string{permissionGroup})

	d.command.Flags().Uint64("uid", 0, "User ID (UID) for the directory owner")
	d.command.Flags().SetAnnotation("uid", "group", []string{permissionGroup})

	d.command.Flags().Uint64("gid", 0, "Group ID (GID) for the directory group owner")
	d.command.Flags().SetAnnotation("gid", "group", []string{permissionGroup})

	// ===== Metadata & Advanced 分组 =====
	d.command.Flags().String("prefer_mds", "", "Comma-separated list of preferred MDS IDs or group IDs for metadata location")
	d.command.Flags().SetAnnotation("prefer_mds", "group", []string{metadataGroup})

	d.command.Flags().Bool("not_use_mirror", false, "Disable mirroring for this directory")
	d.command.Flags().SetAnnotation("not_use_mirror", "group", []string{metadataGroup})

	d.command.Flags().Bool("casefold", false, "Enable case-insensitive folder (casefolding) for the directory")
	d.command.Flags().SetAnnotation("casefold", "group", []string{metadataGroup})

	// ===== 设置自定义帮助模板 =====
	var flaghelper = flagshelper.NewFlagsHelper(flagshelper.WithSpacing(24))
	d.command.SetHelpFunc(func(cmd *cobra.Command, args []string) {
		// 基础帮助信息
		fmt.Fprintf(cmd.OutOrStdout(), "%s\n\n", d.command.Short)
		fmt.Fprintf(cmd.OutOrStdout(), "Usage:\n  %s [flags]\n\n", cmd.CommandPath())

		// 添加 Examples 部分
		if d.command.Example != "" {
			fmt.Fprintf(cmd.OutOrStdout(), "Examples:\n%s\n\n", d.command.Example)
		}

		// 分组显示 flags
		flaghelper.PrintFlagGroup(cmd, targetGroup)
		flaghelper.PrintFlagGroup(cmd, permissionGroup)
		flaghelper.PrintFlagGroup(cmd, metadataGroup)

		// 全局帮助 flag
		fmt.Fprintf(cmd.OutOrStdout(), "\nGlobal Flags:\n  -h, --help   help for %s\n", cmd.Name())
	})
}

PreRunE vs Run

  • PreRunE 负责参数解析和验证,失败时提前返回错误
  • Run 只关注业务逻辑,前提是参数已经正确解析

这种职责分离让代码更加清晰易测。

FlagsHelper 单元测试示例

为了保证 FlagsHelper 的可靠性,建议添加单元测试。以下是一个简单的测试示例:

go
package flagshelper

import (
	"bytes"
	"testing"

	"github.com/spf13/cobra"
)

func TestFlagsHelper_PrintFlagGroup(t *testing.T) {
	cmd := &cobra.Command{Use: "test"}
	cmd.Flags().String("name", "default", "test flag description")
	cmd.Flags().SetAnnotation("name", "group", []string{"TestGroup"})

	// 捕获输出
	buf := new(bytes.Buffer)
	cmd.SetOut(buf)

	helper := NewFlagsHelper(WithSpacing(20))
	helper.PrintFlagGroup(cmd, "TestGroup")

	output := buf.String()
	expected := "\nTestGroup:\n  --name              test flag description (default: default)\n"

	if output != expected {
		t.Errorf("expected:\n%s\ngot:\n%s", expected, output)
	}
}

这个测试覆盖了:

  • Flag 分组标签的正确识别
  • 默认值的正确显示
  • 对齐格式的正确性

在实际项目中,建议为每个分组和边界情况(如空字符串默认值、长 flag 名称等)添加测试用例。

优化与扩展建议

1. 示例缩进优化

如果希望示例输出更美观,可以在 Example 字符串中添加缩进:

go
Example: `  # Create a directory with default settings
  agentctl mkdir --path /data/new_folder

  # Create with specific permissions and ownership
  agentctl mkdir --path /data/project --access_mode 0750 --uid 1001 --gid 1001

  # Create with case-insensitive support
  agentctl mkdir --path /data/shared --casefold --prefer_mds "mds1,mds2"`,

2. 支持子命令分组

如果命令有多个子命令,可以考虑使用类似的方式对子命令进行分组展示。

3. 彩色输出

结合 github.com/logrusorgru/aurora 等库,可以为不同分组添加颜色:

go
fmt.Fprintf(cmd.OutOrStdout(), "\n%s:\n", aurora.Cyan(groupName))

4. 配置化分组定义

对于大型项目,可以考虑将分组定义抽离到配置文件中,实现更灵活的管理。

5. 自定义其他 Annotation

除了 group,你还可以定义其他 Annotation 键名:

go
// 标记废弃的 flag
cmd.Flags().SetAnnotation("old_flag", "deprecated", []string{"true"})

// 在 HelpFunc 中特殊渲染
if deprecated, ok := flag.Annotations["deprecated"]; ok && deprecated[0] == "true" {
    // 以灰色或删除线样式输出
}

总结

本文通过一个完整的实战案例,展示了如何为 Cobra 命令实现自定义的 Flag 分组显示。核心方案包括:

  1. FlagsHelper:通用的分组打印辅助组件
  2. Flag Annotations:利用 Cobra 的注解机制标记分组
  3. 自定义 HelpFunc:接管帮助信息的输出格式

这套方案的优点在于:

  • 代码量小:核心代码不超过 100 行
  • 易于集成:可以快速应用到任意 Cobra 命令
  • 可扩展性强:Functional Options 模式让配置灵活
  • 提升用户体验:帮助信息一目了然

无论你是构建企业级 CLI 工具还是开源项目,这种实现都能显著提升工具的专业度。希望这篇文章对你有所帮助!


相关资源:

相关博文

附加:flagshelper 包完整实现

为了博文的完整性,以及方便你理解博文中的相关概念,下面是 flagshelper 包的完整实现,你可以直接复制使用。

cmd/agentctl/helper/flagshelper/flagshelper.go
go
package flagshelper

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

type Option func(flagshelper *FlagsHelper)

func WithSpacing(spacing int) Option {
	return func(flagshelper *FlagsHelper) {
		flagshelper.spacing = spacing
	}
}

type FlagsHelper struct {
	spacing int
}

func NewFlagsHelper(options ...Option) *FlagsHelper {
	f := &FlagsHelper{spacing: 20}
	for _, ops := range options {
		ops(f)
	}
	return f
}

// PrintFlagGroup 辅助函数,打印分组flags(默认值显示在同一行)
func (f *FlagsHelper) PrintFlagGroup(cmd *cobra.Command, groupName string) {
	fmt.Fprintf(cmd.OutOrStdout(), "\n%s:\n", groupName)
	cmd.LocalFlags().VisitAll(func(flag *pflag.Flag) {
		if groups, ok := flag.Annotations["group"]; ok {
			for _, g := range groups {
				if g == groupName {
					// 构建默认值显示部分
					defaultStr := ""
					if flag.DefValue != "" && flag.DefValue != "[]" {
						defaultStr = fmt.Sprintf(" (default: %v)", flag.DefValue)
					}

					// 计算对齐间距(保持至少2个空格的间隔)
					flagName := "--" + flag.Name
					spacing := f.spacing - len(flagName)
					if spacing < 2 {
						spacing = 2
					}

					// 输出格式化后的flag信息
					fmt.Fprintf(cmd.OutOrStdout(), "  %-*s%s%s\n",
						len(flagName)+spacing,
						flagName,
						flag.Usage,
						defaultStr)
				}
			}
		}
	})
}
最后更新2026/09/01 16:07
如果你觉得这篇文章有帮助,或者想聊聊技术、工作,欢迎通过下面方式联系我:
contact fishfinal