# qflag
**Repository Path**: MM-Q/qflag
## Basic Information
- **Project Name**: qflag
- **Description**: QFlag 是一个专为 Go 语言设计的命令行参数解析库, 提供了丰富的功能和优雅的 API, 帮助开发者快速构建专业的命令行工具。它支持多种标志类型、子命令、环境变量绑定、自动补全等高级特性, 同时保持简单易用的设计理念。
- **Primary Language**: Go
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2025-06-13
- **Last Updated**: 2026-03-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Go语言, 参数解析, Cli
## README
# 🚀 QFlag
[](https://golang.org/) [](LICENSE) [](https://opensource.org/licenses/MIT) [](https://gitee.com/MM-Q/qflag) [](https://github.com/QiaoMuDe/qflag) [](https://deepwiki.com/QiaoMuDe/qflag)
*泛型设计 • 自动路由 • 类型安全 • 并发安全 • 自动补全 • 子命令管理*
---
## 📖 项目简介
QFlag 是一个专为 Go 语言设计的命令行参数解析库, 提供了丰富的功能和优雅的 API, 帮助开发者快速构建专业的命令行工具。它支持多种标志类型、子命令、环境变量绑定、自动补全等高级特性, 同时保持简单易用的设计理念。
### ✨ 核心特性
- 🎯 **类型安全** - 支持多种标志类型, 确保类型安全
- 🚀 **高性能** - 优化的解析算法, 快速高效
- 🛡️ **错误处理** - 结构化的错误类型, 便于调试和处理
- 🌍 **国际化** - 支持中文和英文双语
- 🔄 **环境变量** - 自动绑定环境变量
- 📝 **自动补全** - 生成 Bash 和 PowerShell 补全脚本
- 🎨 **帮助生成** - 自动生成专业的帮助文档
- 🔗 **互斥标志** - 支持标志互斥组
- ✅ **必需标志** - 支持标志必需组和条件性必需组
- 🌳 **子命令** - 完整的子命令支持
---
## 🔗 项目地址
该项目同时托管在 Gitee 和 GitHub 上,您可以选择合适的平台访问:
| 平台 | 地址 | 描述 |
| ------------------ | ----------------------------------------------------------- | -------------------------- |
| 🔴**Gitee** | [gitee.com/MM-Q/qflag](https://gitee.com/MM-Q/qflag) | 国内访问更快,主要开发仓库 |
| ⚫**GitHub** | [github.com/QiaoMuDe/qflag](https://github.com/QiaoMuDe/qflag) | 国际化平台,同步更新 |
---
## 📦 安装指南
使用 `go get` 命令安装:
```bash
go get -u gitee.com/MM-Q/qflag
```
然后在代码中导入:
```go
import "gitee.com/MM-Q/qflag"
```
---
## 💡 使用示例
### 🚀 全局根命令 (推荐)
QFlag 提供了全局根命令 `qflag.Root`, 这是最简单、最直接的使用方式。**推荐优先使用**全局根命令作为命令行工具的入口点。
```go
package main
import (
"fmt"
"gitee.com/MM-Q/qflag"
)
func main() {
// 直接使用全局根命令创建标志
name := qflag.Root.String("name", "n", "用户名", "guest")
age := qflag.Root.Int("age", "a", "年龄", 18)
verbose := qflag.Root.Bool("verbose", "v", "详细模式", false)
// 配置全局命令
qflag.Root.SetDesc("示例应用程序")
qflag.Root.SetVersion("1.0.0")
// 解析命令行参数
if err := qflag.Parse(); err != nil {
fmt.Printf("解析错误: %v\n", err)
return
}
// 使用参数
fmt.Printf("用户名: %s\n", name.Get())
fmt.Printf("年龄: %d\n", age.Get())
fmt.Printf("详细模式: %t\n", verbose.Get())
fmt.Printf("非标志参数: %v\n", qflag.Root.Args())
}
```
#### 全局根命令的优势
- 🎯 **简单易用**: 无需手动创建命令实例, 直接使用
- 🚀 **零配置**: 自动使用可执行文件名作为命令名
- 🔧 **功能完整**: 支持所有 QFlag 的高级功能
- 📦 **统一入口**: 所有操作都通过 `qflag.Root` 访问
#### 全局根命令支持的便捷函数
```go
// 解析函数
qflag.Parse() // 解析命令行参数
qflag.ParseOnly() // 仅解析当前命令
qflag.ParseAndRoute() // 解析并路由到子命令
// 子命令管理
qflag.AddSubCmds(cmd1, cmd2) // 添加子命令
qflag.AddSubCmdFrom([]Command{cmd1, cmd2}) // 从切片添加子命令
// 互斥组
qflag.AddMutexGroup("format", []string{"json", "xml"}, false)
// 必需组
qflag.AddRequiredGroup("connection", []string{"host", "port"}, false) // 普通必需组
qflag.AddRequiredGroup("database", []string{"dbhost", "dbport"}, true) // 条件性必需组
```
### 基础用法
```go
package main
import (
"fmt"
"os"
"gitee.com/MM-Q/qflag"
)
func main() {
// 创建命令
cmd := qflag.NewCmd("myapp", "m", qflag.ContinueOnError)
cmd.SetDesc("我的应用程序")
cmd.SetVersion("1.0.0")
// 使用便捷方法创建标志
nameFlag := cmd.String("name", "n", "用户名", "guest")
verboseFlag := cmd.Bool("verbose", "v", "详细输出", false)
// 解析参数
if err := cmd.Parse(os.Args[1:]); err != nil {
fmt.Printf("参数解析错误: %v\n", err)
os.Exit(1)
}
// 使用参数
fmt.Printf("用户名: %s\n", nameFlag.GetStr())
fmt.Printf("详细模式: %v\n", verboseFlag.IsSet())
}
```
### 高级用法
#### 使用全局根命令的子命令支持
```go
package main
import (
"fmt"
"gitee.com/MM-Q/qflag"
)
func main() {
// 配置全局根命令
qflag.Root.SetDesc("命令行工具")
qflag.Root.SetVersion("1.0.0")
// 创建全局标志
verbose := qflag.Root.Bool("verbose", "v", "详细输出", false)
// 创建子命令
listCmd := qflag.NewCmd("list", "ls", qflag.ContinueOnError)
listCmd.SetDesc("列出所有项目")
listCmd.Bool("all", "a", "显示所有项目", false)
addCmd := qflag.NewCmd("add", "a", qflag.ContinueOnError)
addCmd.SetDesc("添加新项目")
addCmd.String("name", "n", "项目名称", "")
// 添加子命令到全局根命令
qflag.AddSubCmds(listCmd, addCmd)
// 解析并路由
if err := qflag.ParseAndRoute(); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
// 如果是根命令执行
if qflag.Root.NArg() == 0 {
fmt.Printf("详细模式: %t\n", verbose.Get())
fmt.Println("使用 'help' 查看可用命令")
}
}
```
#### 传统子命令支持
```go
package main
import (
"fmt"
"os"
"gitee.com/MM-Q/qflag"
)
func main() {
// 创建根命令
rootCmd := qflag.NewCmd("cli", "", qflag.ContinueOnError)
rootCmd.SetDesc("命令行工具")
// 使用便捷方法创建子命令
listCmd := qflag.NewCmd("list", "ls", qflag.ContinueOnError)
listCmd.SetDesc("列出所有项目")
listCmd.Bool("all", "a", "显示所有项目", false)
addCmd := qflag.NewCmd("add", "a", qflag.ContinueOnError)
addCmd.SetDesc("添加新项目")
addCmd.String("name", "n", "项目名称", "")
// 添加子命令
rootCmd.AddSubCmds(listCmd, addCmd)
// 解析并路由
if err := rootCmd.ParseAndRoute(os.Args[1:]); err != nil {
fmt.Printf("错误: %v\n", err)
os.Exit(1)
}
}
```
#### 便捷方法创建标志
```go
package main
import (
"fmt"
"os"
"time"
"gitee.com/MM-Q/qflag"
)
func main() {
cmd := qflag.NewCmd("server", "s", qflag.ContinueOnError)
// 使用便捷方法创建多个标志
cmd.String("host", "h", "主机地址", "localhost")
cmd.Uint("port", "p", "端口号", 8080)
cmd.Duration("timeout", "t", "超时时间", time.Second*30)
cmd.Bool("debug", "d", "调试模式", false)
fmt.Printf("成功添加 %d 个标志\n", len(cmd.Flags()))
}
```
#### 使用全局根命令的互斥标志组
```go
package main
import (
"fmt"
"gitee.com/MM-Q/qflag"
)
func main() {
// 配置全局根命令
qflag.Root.SetDesc("格式转换工具")
// 使用全局根命令创建互斥标志
jsonFlag := qflag.Root.Bool("json", "j", "JSON 格式", false)
xmlFlag := qflag.Root.Bool("xml", "x", "XML 格式", false)
yamlFlag := qflag.Root.Bool("yaml", "y", "YAML 格式", false)
// 添加互斥组到全局根命令
qflag.AddMutexGroup("format", []string{"json", "xml", "yaml"}, false)
// 解析参数
if err := qflag.Parse(); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
// 使用参数
if jsonFlag.Get() {
fmt.Println("使用 JSON 格式")
} else if xmlFlag.Get() {
fmt.Println("使用 XML 格式")
} else if yamlFlag.Get() {
fmt.Println("使用 YAML 格式")
}
}
```
#### 传统互斥标志组
```go
package main
import (
"fmt"
"os"
"gitee.com/MM-Q/qflag"
)
func main() {
cmd := qflag.NewCmd("converter", "", qflag.ContinueOnError)
// 使用便捷方法创建互斥标志
jsonFlag := cmd.Bool("json", "j", "JSON 格式", false)
xmlFlag := cmd.Bool("xml", "x", "XML 格式", false)
yamlFlag := cmd.Bool("yaml", "y", "YAML 格式", false)
// 创建互斥标志组
formatGroup := qflag.NewMutexGroup("format", "输出格式", true)
formatGroup.AddFlags(jsonFlag, xmlFlag, yamlFlag)
cmd.AddMutexGroup(formatGroup)
// 解析参数
if err := cmd.Parse(os.Args[1:]); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
}
```
#### 使用全局根命令的必需标志组
```go
package main
import (
"fmt"
"gitee.com/MM-Q/qflag"
)
func main() {
// 配置全局根命令
qflag.Root.SetDesc("数据库连接工具")
// 使用全局根命令创建必需标志
hostFlag := qflag.Root.String("host", "h", "主机地址", "")
portFlag := qflag.Root.Uint("port", "p", "端口号", 0)
// 添加普通必需组到全局根命令 - 所有标志都必须设置
qflag.AddRequiredGroup("connection", []string{"host", "port"}, false)
// 添加条件性必需组 - 如果使用其中一个则必须同时使用
qflag.AddRequiredGroup("database", []string{"dbhost", "dbport"}, true)
// 解析参数
if err := qflag.Parse(); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
// 使用参数
fmt.Printf("连接到 %s:%d\n", hostFlag.Get(), portFlag.Get())
}
```
#### 传统必需标志组
```go
package main
import (
"fmt"
"os"
"gitee.com/MM-Q/qflag"
)
func main() {
cmd := qflag.NewCmd("db-connect", "", qflag.ContinueOnError)
// 使用便捷方法创建必需标志
hostFlag := cmd.String("host", "h", "主机地址", "")
portFlag := cmd.Uint("port", "p", "端口号", 0)
usernameFlag := cmd.String("username", "u", "用户名", "")
passwordFlag := cmd.String("password", "P", "密码", "")
// 添加普通必需组 - 所有标志都必须设置
cmd.AddRequiredGroup("connection", []string{"host", "port"}, false)
cmd.AddRequiredGroup("auth", []string{"username", "password"}, false)
// 添加条件性必需组 - 如果使用其中一个则必须同时使用
cmd.AddRequiredGroup("optional-features", []string{"feature-a", "feature-b"}, true)
// 解析参数
if err := cmd.Parse(os.Args[1:]); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
// 使用参数
fmt.Printf("连接到 %s:%d\n", hostFlag.Get(), portFlag.Get())
fmt.Printf("用户: %s\n", usernameFlag.Get())
}
```
#### 条件性必需组
条件性必需组是QFlag提供的一种灵活的标志验证方式,它允许您定义一组标志,如果组中任何一个标志被使用,则所有标志都必须被设置。这与普通必需组不同,普通必需组要求所有标志都必须被设置,无论是否使用了其中任何一个。
```go
package main
import (
"fmt"
"gitee.com/MM-Q/qflag"
)
func main() {
// 配置全局根命令
qflag.Root.SetDesc("数据库连接工具")
// 创建条件性必需组的标志
dbHostFlag := qflag.Root.String("dbhost", "dh", "数据库主机", "")
dbPortFlag := qflag.Root.Uint("dbport", "dp", "数据库端口", 0)
dbUserFlag := qflag.Root.String("dbuser", "du", "数据库用户", "")
dbPassFlag := qflag.Root.String("dbpass", "dp", "数据库密码", "")
// 添加条件性必需组 - 如果使用其中一个则必须同时使用
qflag.AddRequiredGroup("database", []string{"dbhost", "dbport", "dbuser", "dbpass"}, true)
// 解析参数
if err := qflag.Parse(); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
// 使用参数
if dbHostFlag.IsSet() {
fmt.Printf("数据库连接: %s:%d, 用户: %s\n",
dbHostFlag.Get(), dbPortFlag.Get(), dbUserFlag.Get())
} else {
fmt.Println("未使用数据库连接")
}
}
```
**条件性必需组的使用场景:**
1. **可选功能模块**: 当应用程序有多个可选功能模块,每个模块需要一组相关的配置参数时
2. **可选连接**: 当应用程序可以连接到多个可选的服务,每个服务需要自己的连接参数时
3. **可选输出格式**: 当应用程序支持多种输出格式,每种格式需要特定的参数时
**普通必需组 vs 条件性必需组:**
- **普通必需组**: 组中的所有标志都必须被设置,无论是否使用了其中任何一个
- **条件性必需组**: 只有当组中任何一个标志被设置时,所有标志才必须被设置
#### 环境变量绑定
```go
package main
import (
"fmt"
"os"
"gitee.com/MM-Q/qflag"
)
func main() {
cmd := qflag.NewCmd("app", "", qflag.ContinueOnError)
// 设置环境变量前缀
cmd.SetEnvPrefix("MYAPP")
// 使用便捷方法创建并绑定环境变量的标志
dbFlag := cmd.String("database", "d", "数据库地址", "localhost")
dbFlag.BindEnv("DATABASE_URL")
// 解析参数
if err := cmd.Parse(os.Args[1:]); err != nil {
fmt.Printf("错误: %v\n", err)
return
}
fmt.Printf("数据库地址: %s\n", dbFlag.GetStr())
}
```
---
## 📚 API 文档概述
QFlag 提供了简洁而强大的 API, 主要包含以下核心组件:
### 🚀 全局根命令 (推荐使用方式)
QFlag 提供了全局根命令 `qflag.Root`, 这是最简单、最直接的使用方式。**推荐优先使用**全局根命令作为命令行工具的入口点。
#### 全局根命令的优势
- 🎯 **简单易用**: 无需手动创建命令实例, 直接使用
- 🚀 **零配置**: 自动使用可执行文件名作为命令名
- 🔧 **功能完整**: 支持所有 QFlag 的高级功能
- 📦 **统一入口**: 所有操作都通过 `qflag.Root` 访问
#### 全局根命令支持的便捷函数
```go
// 解析函数
qflag.Parse() // 解析命令行参数
qflag.ParseOnly() // 仅解析当前命令
qflag.ParseAndRoute() // 解析并路由到子命令
// 子命令管理
qflag.AddSubCmds(cmd1, cmd2) // 添加子命令
qflag.AddSubCmdFrom([]Command{cmd1, cmd2}) // 从切片添加子命令
// 互斥组
qflag.AddMutexGroup("format", []string{"json", "xml"}, false)
```
#### 全局根命令的使用方式
```go
// 直接使用全局根命令创建标志
name := qflag.Root.String("name", "n", "用户名", "guest")
age := qflag.Root.Int("age", "a", "年龄", 18)
verbose := qflag.Root.Bool("verbose", "v", "详细模式", false)
// 配置全局命令
qflag.Root.SetDesc("示例应用程序")
qflag.Root.SetVersion("1.0.0")
// 解析命令行参数
if err := qflag.Parse(); err != nil {
fmt.Printf("解析错误: %v\n", err)
return
}
```
### 核心概念
- **Command (命令) ** - 命令行工具的核心, 支持标志管理、参数解析、子命令等功能
- **Flag (标志) ** - 命令行参数的抽象, 支持多种数据类型
- **MutexGroup (互斥组) ** - 确保组内只有一个标志被设置
- **RequiredGroup (必需组) ** - 确保组内所有标志都被设置, 支持普通必需组和条件性必需组两种模式
### 便捷方法
Command 类型提供了丰富的便捷方法来创建各种类型的标志, 无需手动创建和添加标志:
```go
// 字符串和布尔标志
nameFlag := cmd.String("name", "n", "用户名", "guest")
verboseFlag := cmd.Bool("verbose", "v", "详细输出", false)
// 数值类型标志
portFlag := cmd.Uint("port", "p", "端口号", 8080)
timeoutFlag := cmd.Duration("timeout", "t", "超时时间", time.Second*30)
// 集合类型标志
filesFlag := cmd.StringSlice("files", "f", "文件列表", []string{})
tagsFlag := cmd.IntSlice("tags", "", "标签列表", []int{})
```
### 详细的 API 文档
完整的 API 文档和示例代码, 请参考项目中的 `examples/` 目录和源代码中的注释。
### 📚 标志使用语法
详细的标志使用语法和高级功能说明, 请参考 [FLAG_USAGE.md](FLAG_USAGE.md)。
---
## 🎯 支持的功能
### 标志功能
- ✅ 短标志名 (单字符, 如 `-v`)
- ✅ 长标志名 (多字符, 如 `--verbose`)
- ✅ 默认值设置
- ✅ 必需标志验证
- ✅ 条件性必需组验证
- ✅ 标志描述
- ✅ 环境变量绑定
- ✅ 标志值验证
- ✅ 枚举值限制
- ✅ 切片类型支持
### 命令功能
- ✅ 子命令支持
- ✅ 命令别名
- ✅ 命令描述
- ✅ 版本信息
- ✅ 帮助信息
- ✅ 示例展示
- ✅ 注意事项
### 高级功能
- ✅ 互斥标志组
- ✅ 必需标志组
- ✅ 条件性必需组
- ✅ 自动补全脚本生成
- ✅ 环境变量前缀
- ✅ 错误处理策略
- ✅ 中文/英文双语支持
- ✅ Logo 文本设置
- ✅ 使用语法自定义
---
## ⚙️ 配置选项说明
### 错误处理策略
QFlag 提供了三种错误处理策略:
- **ContinueOnError** - 遇到错误继续解析
- **ExitOnError** - 遇到错误立即退出
- **ReturnOnError** - 遇到错误返回错误
### 命令配置
通过 `CmdConfig` 可以自定义命令的各种行为, 包括版本信息、语言设置、环境变量前缀等。详细的配置选项请参考源代码中的注释。
---
## 📁 项目结构
```
qflag/
├── internal/ # 内部实现
│ ├── builtin/ # 内置标志 (help, version, completion)
│ ├── cmd/ # 命令实现
│ ├── completion/ # 自动补全脚本生成
│ ├── flag/ # 标志类型实现
│ ├── parser/ # 参数解析器
│ ├── registry/ # 注册表实现
│ ├── testutils/ # 测试工具
│ ├── types/ # 类型定义
│ └── utils/ # 工具函数
├── examples/ # 使用示例
├── exports.go # 公共 API 导出
├── qflag.go # 全局根命令和便捷函数
├── go.mod # Go 模块文件
└── README.md # 项目文档
```
---
## 🧪 测试说明
### 运行测试
```bash
# 运行所有测试
go test ./...
# 运行特定包的测试
go test ./internal/cmd
# 运行测试并显示覆盖率
go test -cover ./...
# 生成覆盖率报告
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
```
### 测试覆盖
项目使用全面的测试套件, 包括:
- 单元测试
- 集成测试
- 边界条件测试
- 错误处理测试
---
## 📄 许可证和贡献指南
### 许可证
本项目采用 MIT 许可证。详见 [LICENSE](LICENSE) 文件。
### 贡献指南
我们欢迎任何形式的贡献!
#### 贡献方式
1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 创建 Pull Request
#### 代码规范
- 遵循 Go 语言代码规范
- 添加适当的注释
- 编写测试用例
- 确保所有测试通过
- 更新相关文档
#### 问题反馈
如果您发现 bug 或有功能建议, 请:
- 搜索现有的 issues
- 创建新的 issue, 详细描述问题
- 提供复现步骤和环境信息
---
## 📞 联系方式和相关链接
### 相关资源
- 📦 **仓库地址**: [https://gitee.com/MM-Q/qflag.git](https://gitee.com/MM-Q/qflag.git)
- 📖 **文档**: [项目文档](https://gitee.com/MM-Q/qflag)
- 🐛 **问题反馈**: [Issues](https://gitee.com/MM-Q/qflag/issues)
- 💬 **讨论**: [Discussions](https://gitee.com/MM-Q/qflag/discussions)
### 联系方式
- 📧 **邮箱**: [提交 Issue](https://gitee.com/MM-Q/qflag/issues)
---
## 🙏 致谢
感谢所有为本项目做出贡献的开发者!
---
**[⬆ 返回顶部](#qflag)**
Made with ❤️ by QFlag Team