logo
0
0
WeChat Login

envx

一个基于 Go 泛型的优雅环境变量管理库,提供类型安全的配置获取与转换功能。

📦 项目概述

envx 是一个轻量级、高性能的 Go 环境变量处理库。它利用 Go 1.18+ 引入的泛型特性,实现了类型安全的环境变量获取和自动转换功能,让配置管理变得更加简洁和安全。

✨ 核心特性

  • 🎯 泛型支持:使用 Go 泛型实现类型安全的 API,编译时检查类型错误
  • 🔄 自动类型转换:支持多种常见类型的自动转换,无需手动解析
  • ⚡ 零依赖:纯 Go 实现,不依赖任何第三方库
  • 🛡️ 安全默认值:转换失败时安全返回默认值,避免程序崩溃
  • 📊 丰富类型:支持 int、int64、float、bool、string、time.Time 等多种类型
  • 🎨 自定义类型:提供 Duration、Time、Date、Array、Map 等高级类型
  • 🧪 完整测试:覆盖所有功能点的单元测试,确保可靠性

🚀 快速开始

安装

go get github.com/cnb.cool/jun3.work/cloud/envx

或添加模块依赖(根据实际仓库地址调整):

# 在 go.mod 中添加 module your/project go 1.24 require cnb.cool/jun3.work/cloud/envx v1.0.0

基本用法

package main import ( "fmt" "cnb.cool/jun3.work/cloud/envx" ) func main() { // 获取整数类型环境变量 port := envx.Get[int]("PORT", 8080) fmt.Printf("Port: %d\n", port) // 获取字符串类型环境变量 name := envx.Get[string]("APP_NAME", "default") fmt.Printf("Name: %s\n", name) // 获取布尔类型环境变量 debug := envx.Get[bool]("DEBUG", false) fmt.Printf("Debug: %v\n", debug) // 获取浮点数类型环境变量 timeout := envx.Get[float64]("TIMEOUT", 30.0) fmt.Printf("Timeout: %f\n", timeout) }

📖 使用说明

核心函数

Get[T any](key string, defaultValue T) T

安全地获取并转换环境变量值。

参数说明:

  • key: 环境变量键名
  • defaultValue: 当键不存在或转换失败时返回的默认值
  • 返回值: 转换后的类型 T 或默认值

支持类型:

  • 数值类型:int, int64, float64, float32
  • 布尔类型:bool
  • 字符串:string
  • 时间类型:time.Time, envx.Time, envx.Date
  • 数组类型:[]string, []float64, []int, []int64
  • 映射类型:map[string]string, map[string]interface{}

高级用法

1. 时间类型

import ( "cnb.cool/jun3.work/cloud/envx" "time" ) // 获取时间类型 exp := envx.Get[envx.Time]("EXPIRY", envx.NowTime()) fmt.Println(exp.String()) // RFC3339 格式 // 获取日期类型 startDate := envx.Get[envx.Date]("START_DATE", envx.TodayDate()) fmt.Println(startDate.String()) // 2026-04-15 格式 // 时间操作 fmt.Println(exp.Unix()) // Unix 时间戳 fmt.Println(exp.Year()) // 年份 fmt.Println(exp.Month()) // 月份 // 日期操作 fmt.Println(startDate.AddDays(7)) // 7 天后 fmt.Println(startDate.IsWeekend()) // 是否周末 fmt.Println(startDate.IsWorkday()) // 是否工作日

2. 时长类型 (Duration)

import "cnb.cool/jun3.work/cloud/envx" // 解析时长字符串 dur, err := envx.ConvertToDuration("1h30m") if err != nil { panic(err) } // 使用自定义 Duration 类型 duration := envx.NewDuration(dur) fmt.Println(duration.String()) // 1h30m0s fmt.Println(duration.Hours()) // 1.5 // 时长运算 newDur := duration.Add(envx.NewDuration(30 * time.Minute)) newDur = duration.Multiply(2) newDur = duration.Divide(3) // 时长比较 if duration.Greater(other) { fmt.Println("当前时长更长") } // 时长格式化 fmt.Println(envx.DurationString(dur))

3. 数组类型 (Array)

import "cnb.cool/jun3.work/cloud/envx" // 创建数组 arr := envx.NewArray("apple", "banana", "cherry") // 数组操作 arr = arr.Append("date") // 追加元素 arr = arr.Prepend("apricot") // 前置元素 arr = arr.RemoveValue("banana") // 移除元素 // 数组查询 if arr.Contains("apple") { fmt.Println("包含苹果") } // 数组转换 arr = arr.Unique() // 去重 arr = arr.Sort() // 排序 arr = arr.Reverse() // 反转 // 数组信息 fmt.Println(arr.Len()) // 长度 fmt.Println(arr.Join(",")) // 连接成字符串

4. 映射类型 (Map)

import "cnb.cool/jun3.work/cloud/envx" // 创建映射 m := envx.NewMap("name", "John", "age", "30") // 映射操作 m = m.Set("city", "Beijing") // 设置键值 value, exists := m.Get("name") // 获取值 m, removed := m.Remove("age") // 移除键 // 映射查询 if m.Contains("city") { fmt.Println("包含城市信息") } // 映射信息 keys := m.Keys() // 获取所有键 values := m.Values() // 获取所有值 fmt.Println(m.Len()) // 映射大小

5. 尝试获取模式

import "cnb.cool/jun3.work/cloud/envx" // TryGet: 检查键是否存在 val, exists := envx.TryGet("DATABASE_URL") if exists { fmt.Println("数据库配置:", val) } // TryGetWithDefault: 尝试获取并转换,返回转换结果和成功标志 port, ok := envx.TryGetWithDefault[int]("PORT", 8080) if ok { fmt.Println("端口:", port) } else { fmt.Println("使用默认端口:", port) }

支持的转换格式

布尔类型 (bool)

  • true, 1, yes, y, ontrue
  • false, 0, no, n, offfalse

时长类型 (Duration)

  • 数字 + 单位:30s, 1m, 1h, 24h
  • 支持单位:ns, us, µs, ms, s, m, h
  • 标准格式:1h30m, 2h45m30s

时间类型 (Time)

  • RFC3339: 2006-01-02T15:04:05Z07:00
  • 简洁格式:2006-01-02T15:04:05
  • 空格格式:2006-01-02 15:04:05
  • 日期格式:2006-01-02
  • 其他格式:01/02/2006, 2006/01/02

📁 目录结构

envx/ ├── README.md # 项目文档(本文件) ├── go.mod # Go 模块定义 ├── converters.go # 类型转换函数和自定义类型定义 ├── get.go # 泛型 Get 函数实现 ├── utils.go # 工具函数和辅助功能 ├── get_test.go # 单元测试文件 └── .gitignore # Git 忽略规则

文件说明

文件说明
converters.go包含所有类型转换函数和自定义类型(Duration、Time、Date、Array、Map)
get.go泛型 Get 函数实现,处理类型自动转换逻辑
utils.go工具函数(TryGet、TryGetWithDefault)和系统检测函数
get_test.go完整的单元测试,覆盖所有功能点

🧪 测试

运行测试套件:

# 运行所有测试 go test -v # 运行特定测试 go test -v -run TestGet_Int # 生成测试覆盖率报告 go test -v -cover # 查看覆盖率详情 go test -v -coverprofile=coverage.out && go tool cover -html=coverage.out

测试覆盖范围:

  • ✅ 整数类型转换(int, int64)
  • ✅ 浮点类型转换(float32, float64)
  • ✅ 布尔类型转换
  • ✅ 字符串类型获取
  • ✅ 时间类型转换
  • ✅ 数组和映射类型解析
  • ✅ 键不存在情况处理
  • ✅ 转换失败安全兜底
  • ✅ 空值处理

🛠️ 技术栈

  • 语言: Go 1.24+
  • 特性: Go Generics (泛型)
  • 测试: Go Testing Framework
  • 依赖: 无(纯 Go 标准库)

📚 最佳实践

1. 配置管理

// 定义配置结构 type Config struct { Port int Debug bool Timeout float64 Expiry envx.Time Features envx.Array } // 加载配置 func LoadConfig() Config { return Config{ Port: envx.Get[int]("PORT", 8080), Debug: envx.Get[bool]("DEBUG", false), Timeout: envx.Get[float64]("TIMEOUT", 30.0), Expiry: envx.Get[envx.Time]("EXPIRY", envx.NowTime()), Features: envx.Get[envx.Array]("FEATURES", envx.NewArray()), } }

2. 环境变量验证

// 使用 TryGetWithDefault 进行验证 if port, ok := envx.TryGetWithDefault[int]("PORT", 0); !ok || port <= 0 { log.Fatal("无效的环境变量:PORT") }

3. 默认值设置

// 合理设置默认值,确保应用不会因缺失配置而崩溃 maxRetries := envx.Get[int]("MAX_RETRIES", 3) // 默认重试 3 次 logLevel := envx.Get[string]("LOG_LEVEL", "info") // 默认日志级别

🤝 贡献指南

欢迎贡献代码!以下是参与项目的方式:

开发流程

  1. Fork 本仓库
  2. 创建分支git checkout -b feature/your-feature-name
  3. 提交更改git commit -m 'Add your feature'
  4. 推送分支git push origin feature/your-feature-name
  5. 提交 PR

代码规范

  • 遵循 Go 官方代码风格指南
  • 所有新增功能必须包含单元测试
  • 保持代码简洁,注释清晰
  • 提交信息使用英文,采用命令式语气

提交信息格式

<type>: <subject> [optional body]

常见类型:

  • feat: 新功能
  • fix: 修复 bug
  • docs: 文档更新
  • style: 代码格式调整
  • refactor: 重构
  • test: 测试相关
  • chore: 构建/工具相关

📄 许可证

本项目采用 MIT 许可证。详见 LICENSE 文件。

MIT License 摘要

  • ✅ 允许商业使用
  • ✅ 允许修改
  • ✅ 允许分发
  • ✅ 允许私有化

唯一要求:分发时需包含原许可证和版权声明

❓ 常见问题

Q: 为什么使用泛型?

A: 泛型提供编译时类型检查,避免运行时类型错误,同时保持 API 的简洁性。

Q: 转换失败时会发生什么?

A: 自动返回默认值,不会抛出异常或 panic,确保应用稳定性。

Q: 支持哪些时间格式?

A: 支持 RFC3339、ISO 8601 等多种常见时间格式,详见文档中的时间类型说明。

Q: 如何自定义类型转换?

A: 目前支持预定义类型,如需自定义类型转换,可参考现有实现添加新类型支持。

📝 更新日志

v1.0.0 (2026-04-15)

  • ✨ 初始版本发布
  • 🎯 实现泛型 Get 函数
  • 🔄 支持 15+ 种类型自动转换
  • 📊 新增 Duration、Time、Date、Array、Map 自定义类型
  • 🧪 完整的单元测试覆盖
  • 📚 完善的文档和示例

🔗 相关链接


注意: 本文档持续更新,请以仓库最新版本为准。

About

No description, topics, or website provided.
Language
Go100%