首次提交:初始化项目代码

This commit is contained in:
sunct
2026-07-31 15:18:32 +08:00
commit d6393266b0
193 changed files with 14287 additions and 0 deletions
View File
+24
View File
@@ -0,0 +1,24 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 方式1:变量绑定
var name string
flag.StringVar(&name, "name", "guest", "用户名")
// 方式2:指针获取
age := flag.Int("age", 18, "用户年龄")
enable := flag.Bool("enable", false, "是否启用功能")
// 解析命令行参数
flag.Parse()
// 输出结果
fmt.Printf("用户名:%s\n", name)
fmt.Printf("年龄:%d\n", *age)
fmt.Printf("功能启用:%t\n", *enable)
}
View File
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"flag"
"fmt"
"os"
"strconv"
)
func main() {
port := flag.Int("port", 8080, "服务端口")
host := flag.String("host", "localhost", "服务绑定主机")
flag.Parse()
// 环境变量仅覆盖未手动传参的配置
if !flag.IsSet("port") {
if envPort := os.Getenv("SERVICE_PORT"); envPort != "" {
if p, err := strconv.Atoi(envPort); err == nil {
*port = p
}
}
}
if !flag.IsSet("host") {
if envHost := os.Getenv("SERVICE_HOST"); envHost != "" {
*host = envHost
}
}
fmt.Printf("最终生效配置:主机=%s,端口=%d\n", *host, *port)
}
+41
View File
@@ -0,0 +1,41 @@
package main
import (
"flag"
"fmt"
"os"
)
func main() {
port := flag.Int("port", 8080, "服务监听端口")
config := flag.String("config", "./config.yaml", "配置文件路径")
// 重写全局帮助信息
flag.Usage = func() {
_, err := fmt.Fprintf(flag.CommandLine.Output(), "=== 服务启动工具 V1.0 ===\n\n")
if err != nil {
return
}
_, err = fmt.Fprintf(flag.CommandLine.Output(), "用法:%s [可选参数]\n\n", os.Args[0])
if err != nil {
return
}
_, err = fmt.Fprintf(flag.CommandLine.Output(), "参数说明:\n")
if err != nil {
return
}
flag.PrintDefaults()
_, err = fmt.Fprintf(flag.CommandLine.Output(), "\n使用示例:\n")
if err != nil {
return
}
_, err = fmt.Fprintf(flag.CommandLine.Output(), " %s -port=8080 -config=app.yaml\n", os.Args[0])
if err != nil {
return
}
}
flag.Parse()
fmt.Printf("服务启动成功,端口:%d,配置文件:%s\n", *port, *config)
}
+59
View File
@@ -0,0 +1,59 @@
package main
import (
"flag"
"fmt"
"strings"
)
// PortRange 自定义端口范围类型,支持 min-max 格式
type PortRange struct {
Min int
Max int
}
// Set 实现Value接口,完成参数解析和合法性校验
func (p *PortRange) Set(s string) error {
parts := strings.Split(s, "-")
if len(parts) != 2 {
return fmt.Errorf("格式错误,端口范围格式必须为 minV-max")
}
var minV, maxV int
_, err1 := fmt.Sscanf(parts[0], "%d", &minV)
_, err2 := fmt.Sscanf(parts[1], "%d", &maxV)
if err1 != nil || err2 != nil {
return fmt.Errorf("端口必须为整数")
}
if minV < 1 || minV > 65535 || maxV < 1 || maxV > 65535 || minV > maxV {
return fmt.Errorf("端口范围必须在1-65535之间,且min <= max")
}
p.Min = minV
p.Max = maxV
return nil
}
// String 实现Value接口,定义默认值与字符串展示
func (p *PortRange) String() string {
if p.Min == 0 && p.Max == 0 {
return "1-65535"
}
return fmt.Sprintf("%d-%d", p.Min, p.Max)
}
// Get 实现Getter接口,返回原始类型,支持类型断言
func (p *PortRange) Get() any {
return *p
}
func main() {
var portRange PortRange
flag.Var(&portRange, "port-range", "端口范围,格式:min-max")
flag.Parse()
fmt.Printf("有效端口范围:[%d, %d]\n", portRange.Min, portRange.Max)
fmt.Printf("类型安全取值:%#v\n", portRange.Get().(PortRange))
}
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"flag"
"fmt"
)
func main() {
port := flag.Int("port", 8080, "服务端口")
flag.Parse()
fmt.Println("动态修改前端口:", *port)
// 动态覆盖参数值
if err := flag.Set("port", "9090"); err != nil {
fmt.Println("参数设置失败:", err)
}
fmt.Println("动态修改后端口:", *port)
// 精准查询参数元信息
if f := flag.Lookup("port"); f != nil {
fmt.Printf("参数详情:名称=%s, 当前值=%s, 默认值=%s, 用途=%s\n",
f.Name, f.Value.String(), f.DefValue, f.Usage)
}
}
+51
View File
@@ -0,0 +1,51 @@
package main
import (
"flag"
"fmt"
"strings"
)
// Environment 运行环境枚举类型
type Environment string
const (
EnvDev Environment = "dev"
EnvTest Environment = "test"
EnvProd Environment = "prod"
)
// 合法环境白名单
var validEnvs = map[Environment]bool{
EnvDev: true,
EnvTest: true,
EnvProd: true,
}
func (e *Environment) Set(s string) error {
env := Environment(strings.ToLower(s))
if !validEnvs[env] {
return fmt.Errorf("无效运行环境,仅支持 dev/test/prod")
}
*e = env
return nil
}
func (e *Environment) String() string {
if *e == "" {
return string(EnvDev)
}
return string(*e)
}
func (e *Environment) Get() any {
return *e
}
func main() {
var env Environment = EnvDev // 默认值为 dev
flag.Var(&env, "env", "运行环境:dev/test/prod")
flag.Parse()
fmt.Printf("当前运行环境:%s\n", env)
}
+20
View File
@@ -0,0 +1,20 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 子命令标准模式:手动捕获错误,不自动退出
fs := flag.NewFlagSet("demo", flag.ContinueOnError)
num := fs.Int("num", 0, "数字参数")
// 传入非法参数
err := fs.Parse([]string{"-num=abc"})
if err != nil {
fmt.Printf("参数解析失败:%v\n", err)
return
}
fmt.Println("参数值:", *num)
}
+22
View File
@@ -0,0 +1,22 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 普通函数参数,传参即触发回调
flag.Func("msg", "自定义消息参数", func(s string) error {
fmt.Println("接收参数消息:", s)
return nil
})
// 布尔函数参数,无值传参触发
flag.BoolFunc("debug", "开启调试模式", func(s string) error {
fmt.Println("调试模式状态:", s)
return nil
})
flag.Parse()
}
+50
View File
@@ -0,0 +1,50 @@
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
)
// FilePath 带合法性校验的文件路径类型
type FilePath string
func (f *FilePath) Set(s string) error {
// 解析绝对路径
absPath, err := filepath.Abs(s)
if err != nil {
return fmt.Errorf("路径解析失败:%w", err)
}
// 校验文件存在且为普通文件
info, err := os.Stat(absPath)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("配置文件不存在:%s", absPath)
}
return fmt.Errorf("文件访问异常:%w", err)
}
if info.IsDir() {
return fmt.Errorf("路径为目录,需传入有效文件路径:%s", absPath)
}
*f = FilePath(absPath)
return nil
}
func (f *FilePath) String() string {
return string(*f)
}
func (f *FilePath) Get() any {
return string(*f)
}
func main() {
var configFile FilePath
flag.Var(&configFile, "config", "必填配置文件路径")
flag.Parse()
fmt.Printf("加载配置文件:%s\n", configFile)
}
+19
View File
@@ -0,0 +1,19 @@
package main
import (
"flag"
"fmt"
)
func main() {
port := flag.Int("port", 8080, "服务端口")
flag.Parse()
// 获取无标记位置参数
args := flag.Args()
if len(args) == 0 {
fmt.Println("请传入配置文件路径")
return
}
fmt.Printf("端口:%d,配置文件:%s\n", *port, args[0])
}
+25
View File
@@ -0,0 +1,25 @@
package main
import (
"flag"
"fmt"
"strings"
)
type StringSlice2 []string
func (s *StringSlice2) Set(val string) error {
*s = append(*s, val)
return nil
}
func (s *StringSlice2) String() string {
return strings.Join(*s, ",")
}
func main() {
var files StringSlice2
flag.Var(&files, "file", "指定多个配置文件,可重复传参")
flag.Parse()
fmt.Printf("文件列表:%#v\n", files)
}
+42
View File
@@ -0,0 +1,42 @@
package main
import (
"flag"
"fmt"
"strings"
)
// StringSlice 支持重复传参的字符串切片类型
type StringSlice []string
// Set 实现参数追加逻辑,覆盖原生覆盖问题
func (s *StringSlice) Set(value string) error {
*s = append(*s, value)
return nil
}
// String 实现字符串展示与零值返回
func (s *StringSlice) String() string {
if len(*s) == 0 {
return "[]"
}
return strings.Join(*s, ",")
}
// Get 实现Getter接口,返回原始切片类型
func (s *StringSlice) Get() any {
return []string(*s)
}
func main() {
var files StringSlice
var tags StringSlice
flag.Var(&files, "file", "指定配置文件,可重复传参")
flag.Var(&tags, "tag", "自定义业务标签,可重复传参")
flag.Parse()
fmt.Printf("文件列表:%v (原始类型:%T)\n", files.Get(), files.Get())
fmt.Printf("标签列表:%v (原始类型:%T)\n", tags.Get(), tags.Get())
}
+38
View File
@@ -0,0 +1,38 @@
package main
import (
"flag"
"fmt"
"os"
)
func main() {
// 初始化子命令FlagSet
startCmd := flag.NewFlagSet("start", flag.ContinueOnError)
stopCmd := flag.NewFlagSet("stop", flag.ContinueOnError)
// 子命令私有参数
var port int
var config string
startCmd.IntVar(&port, "port", 8080, "服务监听端口")
stopCmd.StringVar(&config, "config", "./config.yaml", "服务配置文件")
// 校验子命令是否传入
if len(os.Args) < 2 {
fmt.Println("可用子命令:start / stop")
os.Exit(1)
}
// 路由分发
switch os.Args[1] {
case "start":
_ = startCmd.Parse(os.Args[2:])
fmt.Printf("启动服务成功,端口:%d\n", port)
case "stop":
_ = stopCmd.Parse(os.Args[2:])
fmt.Printf("停止服务,配置文件:%s\n", config)
default:
fmt.Printf("未知子命令:%s\n", os.Args[1])
os.Exit(1)
}
}
+128
View File
@@ -0,0 +1,128 @@
package main
import (
"flag"
"fmt"
"os"
)
// GlobalOptions 全局公共参数,所有子命令共享
type GlobalOptions struct {
Verbose bool // 详细日志模式
Config string // 全局配置文件
}
// SubCommand 通用子命令抽象结构体
type SubCommand struct {
Name string
Description string
Flags *flag.FlagSet
Run func([]string, GlobalOptions) error
}
// 提前声明变量,避免初始化循环引用
var commands map[string]*SubCommand
// init 初始化子命令,将 FlagSet 的绑定与执行逻辑分离
func init() {
// --- 初始化 build 命令 ---
buildCmd := &SubCommand{
Name: "build",
Description: "编译构建项目",
Flags: flag.NewFlagSet("build", flag.ContinueOnError),
}
var buildOutput string
// 在外部绑定参数,而不是在 Run 里面重新创建 FlagSet
buildCmd.Flags.StringVar(&buildOutput, "output", "./dist", "项目构建输出目录")
buildCmd.Run = func(args []string, global GlobalOptions) error {
if err := buildCmd.Flags.Parse(args); err != nil {
return err
}
fmt.Printf("[构建成功] 输出目录:%s,全局详细日志:%t,全局配置:%s\n",
buildOutput, global.Verbose, global.Config)
return nil
}
// --- 初始化 deploy 命令 ---
deployCmd := &SubCommand{
Name: "deploy",
Description: "部署项目到环境",
Flags: flag.NewFlagSet("deploy", flag.ContinueOnError),
}
var deployEnv string
deployCmd.Flags.StringVar(&deployEnv, "env", "dev", "部署环境 dev/test/prod")
deployCmd.Run = func(args []string, global GlobalOptions) error {
if err := deployCmd.Flags.Parse(args); err != nil {
return err
}
fmt.Printf("[部署成功] 目标环境:%s,全局配置文件:%s\n",
deployEnv, global.Config)
return nil
}
// 注册子命令
commands = map[string]*SubCommand{
"build": buildCmd,
"deploy": deployCmd,
}
}
func main() {
// 1. 初始化全局参数 FlagSet(独立隔离)
var global GlobalOptions
globalFlags := flag.NewFlagSet("global", flag.ContinueOnError)
globalFlags.BoolVar(&global.Verbose, "verbose", false, "启用详细日志输出")
globalFlags.StringVar(&global.Config, "config", "./config.yaml", "全局配置文件路径")
// 2. 解析全局参数
// 注意:flag 库遇到第一个非 Flag 参数(即子命令名称)就会停止解析
if err := globalFlags.Parse(os.Args[1:]); err != nil {
if err == flag.ErrHelp {
printHelp(globalFlags)
return
}
fmt.Println("全局参数解析失败:", err)
os.Exit(1)
}
// 3. 获取剩余参数(子命令 + 子命令参数)
remainingArgs := globalFlags.Args()
if len(remainingArgs) == 0 {
printHelp(globalFlags)
os.Exit(1)
}
// 4. 路由分发执行子命令
cmdName := remainingArgs[0]
if cmd, exists := commands[cmdName]; exists {
if err := cmd.Run(remainingArgs[1:], global); err != nil {
if err == flag.ErrHelp {
// 当子命令触发 -h 时,打印该子命令专属的帮助信息
fmt.Printf("\n===== 子命令 [%s] 帮助信息 =====\n", cmd.Name)
fmt.Printf("说明:%s\n\n用法:%s [选项]\n\n选项:\n", cmd.Description, cmd.Name)
cmd.Flags.PrintDefaults()
return
}
fmt.Printf("子命令执行失败:%v\n", err)
os.Exit(1)
}
} else {
fmt.Printf("❌ 未知子命令:%s\n", cmdName)
printHelp(globalFlags)
os.Exit(1)
}
}
// printHelp 统一打印全局帮助信息
func printHelp(globalFlags *flag.FlagSet) {
fmt.Println("===== 项目工程化 CLI 工具 =====")
fmt.Println("用法:tool [全局选项] <子命令> [子命令选项]")
fmt.Println("\n全局选项:")
globalFlags.PrintDefaults()
fmt.Println("\n可用子命令:")
for _, cmd := range commands {
fmt.Printf(" %-10s %s\n", cmd.Name, cmd.Description)
}
fmt.Println("\n提示:使用 'tool <子命令> -h' 查看子命令详细帮助")
}
+62
View File
@@ -0,0 +1,62 @@
package main
import (
"flag"
"fmt"
"time"
)
// CustomTime 自定义时间类型,复用标准库文本序列化接口
type CustomTime time.Time
// MarshalText 实现文本序列化(对应默认值展示)
func (t CustomTime) MarshalText() ([]byte, error) {
return []byte(time.Time(t).Format(time.RFC3339)), nil
}
// UnmarshalText 实现文本反序列化(参数解析核心)
func (t *CustomTime) UnmarshalText(b []byte) error {
parseTime, err := time.Parse(time.RFC3339, string(b))
if err != nil {
return err
}
*t = CustomTime(parseTime)
return nil
}
// 枚举类型示例:自定义运行模式
type RunMode string
const (
ModeDev RunMode = "dev"
ModeProd RunMode = "prod"
)
func (m RunMode) MarshalText() ([]byte, error) {
return []byte(m), nil
}
func (m *RunMode) UnmarshalText(b []byte) error {
val := RunMode(b)
if val != ModeDev && val != ModeProd {
return fmt.Errorf("非法运行模式,仅支持 dev/prod")
}
*m = val
return nil
}
func main() {
// 1. 自定义时间参数 TextVar 绑定
var execTime CustomTime
defaultTime := CustomTime(time.Now())
flag.TextVar(&execTime, "exec-time", defaultTime, "执行时间(RFC3339格式)")
// 2. 自定义枚举参数 TextVar 绑定
var runMode RunMode
flag.TextVar(&runMode, "mode", ModeDev, "运行模式 dev/prod")
flag.Parse()
fmt.Printf("运行模式:%s\n", runMode)
fmt.Printf("执行时间:%s\n", time.Time(execTime).Format(time.RFC3339))
}
+58
View File
@@ -0,0 +1,58 @@
package main
import (
"flag"
"fmt"
"os"
)
// PortValue 自定义端口类型,实现flag.Value接口
type PortValue int
func (p *PortValue) Set(s string) error {
var port int
_, err := fmt.Sscanf(s, "%d", &port)
if err != nil || port < 1 || port > 65535 {
return fmt.Errorf("非法端口,必须为1-65535整数")
}
*p = PortValue(port)
return nil
}
func (p *PortValue) String() string {
return fmt.Sprintf("%d", *p)
}
// EnvValue 枚举环境校验类型
type EnvValue string
func (e *EnvValue) Set(s string) error {
if s != "dev" && s != "prod" {
return fmt.Errorf("仅支持 dev/prod 环境")
}
*e = EnvValue(s)
return nil
}
func (e *EnvValue) String() string {
return string(*e)
}
func main() {
var port PortValue
var env EnvValue
flag.Var(&port, "port", "服务端口 1-65535")
flag.Var(&env, "env", "运行环境 dev/prod")
config := flag.String("config", "", "配置文件路径(必填)")
flag.Parse()
// 后置非空校验
if *config == "" {
fmt.Println("错误:config 参数不能为空")
flag.Usage()
os.Exit(1)
}
fmt.Printf("环境:%s,端口:%d,配置:%s\n", env, port, *config)
}
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"flag"
"fmt"
)
func main() {
// 定义基础参数
flag.Int("port", 8080, "服务监听端口")
flag.String("host", "localhost", "服务绑定主机")
flag.Bool("debug", false, "开启调试模式")
// 解析参数
flag.Parse()
fmt.Println("=== 所有已定义参数(含默认值)===")
flag.VisitAll(func(f *flag.Flag) {
fmt.Printf("参数名:%-10s 默认值:%-10s 说明:%s\n", f.Name, f.DefValue, f.Usage)
})
fmt.Println("\n=== 用户主动传入的参数===")
flag.Visit(func(f *flag.Flag) {
fmt.Printf("参数名:%-10s 当前值:%-10s 已修改:%v\n", f.Name, f.Value.String(), f.Value.String() != f.DefValue)
})
}