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%