env - 环境变量管理库
env 是一个简单易用的环境变量管理库,提供 .env 文件加载、类型转换、分组查询等功能。采用”一次初始化,多次读取”的设计理念,适用于高并发场景。
安装
go get -u go-slim.dev/env快速开始
基础用法
package mainimport ( "log" "go-slim.dev/env")func main() { // 初始化:加载 .env 文件 if err := env.Init(); err != nil { log.Fatal(err) } // 锁定环境变量,防止运行时修改 env.Lock() // 读取环境变量 port := env.Int("PORT", 8080) debug := env.Bool("DEBUG", false) dbHost := env.String("DB_HOST", "localhost") log.Printf("Server running on port %d", port)}.env 文件示例
# 应用配置APP_ENV=developmentAPP_NAME=MyAppPORT=8080DEBUG=true# 数据库配置DB_HOST=localhostDB_PORT=5432DB_NAME=mydbDB_USER=adminDB_PASSWORD=secret# 缓存配置CACHE_DRIVER=redisCACHE_DATABASE=1CACHE_SCOPE=app:核心功能
1. 初始化函数
Init - 初始化环境变量
func Init(root ...string) error说明:
从运行目录加载 .env 文件并初始化环境变量。这是整个库的入口函数。
参数:
root:可选参数,指定.env文件所在目录,不指定则使用当前程序的运行目录
加载顺序:
- 系统环境变量
.env文件.env.local文件(优先级更高,可覆盖.env).env.{APP_ENV}文件(根据APP_ENV变量).env.{APP_ENV}.local文件(优先级最高)
示例:
// 使用当前目录if err := env.Init(); err != nil { log.Fatal(err)}// 指定配置目录if err := env.Init("/path/to/config"); err != nil { log.Fatal(err)}// 多环境配置示例// .env.development, .env.production 会根据 APP_ENV 自动加载注意事项:
- 此函数不是线程安全的,必须在程序启动时单线程调用
- 后加载的文件会覆盖先加载的同名变量
- 文件不存在不会报错,只有读取失败才会返回错误
InitWithDir - 从指定目录初始化
func InitWithDir(dir string) error说明:
从指定的目录加载 .env 文件。与 Init() 的区别是必须提供目录参数。
参数:
dir:.env文件所在目录的绝对路径或相对路径
示例:
// 从指定目录加载if err := env.InitWithDir("/etc/myapp"); err != nil { log.Fatal(err)}Load - 加载指定文件
func Load(filenames ...string) error说明:
加载指定的环境变量文件。可用于加载额外的配置文件。
参数:
filenames:要加载的文件路径列表
示例:
// 初始化后加载额外配置env.Init()env.Load("/path/to/secrets.env")env.Load("/path/to/custom1.env", "/path/to/custom2.env")注意事项:
- 调用
Lock()后无法再调用此函数 - 文件不存在会返回错误
Lock - 锁定环境变量
func Lock()说明:
锁定全局环境变量,防止后续修改。调用后任何写操作(Init、Load、Updates)都会失败。
最佳实践:
在初始化完成后立即调用 Lock(),确保运行时只能读取环境变量。
示例:
func main() { // 初始化阶段 if err := env.Init(); err != nil { log.Fatal(err) } // 锁定,防止运行时修改 env.Lock() // 运行时阶段 - 只能读取 go worker1() go worker2()}特性:
- 锁定是单向的,无法解锁
- 锁定后调用
Load()会返回ErrLocked错误 - 锁定后调用
Updates()或Clean()会导致 panic - 可以重复调用(幂等操作)
2. 查询函数
Lookup - 查询环境变量
func Lookup(name string) (string, bool)说明:
查询指定的环境变量值。
参数:
name:环境变量名
返回值:
- 第一个返回值:变量的字符串值
- 第二个返回值:
true表示变量存在且值非空,false表示不存在或为空
示例:
if value, exists := env.Lookup("API_KEY"); exists { fmt.Println("API Key:", value)} else { fmt.Println("API Key not set")}Exists - 检查变量是否存在
func Exists(name string) bool说明:
检查环境变量是否存在。与 Lookup 的区别是,只要变量被定义就返回 true,即使值为空。
示例:
if env.Exists("DEBUG") { // DEBUG 变量已定义(可能为空)}// 对比 Lookupvalue, exists := env.Lookup("DEBUG")// exists 只有在 DEBUG 存在且非空时才为 trueString - 获取字符串值
func String(name string, fallback ...string) string说明:
返回指定环境变量的字符串值。如果不存在或为空,返回默认值。
参数:
name:环境变量名fallback:可选的默认值(可变参数,只使用第一个)
示例:
// 无默认值,不存在时返回空字符串host := env.String("DB_HOST")// 有默认值host := env.String("DB_HOST", "localhost")name := env.String("APP_NAME", "MyApp")Int - 获取整数值
func Int(name string, fallback ...int) int说明:
返回指定环境变量的整数值。如果不存在、为空或转换失败,返回默认值。
示例:
// 无默认值,失败时返回 0port := env.Int("PORT")// 有默认值port := env.Int("PORT", 8080)maxConn := env.Int("MAX_CONNECTIONS", 100)Float - 获取浮点数值
func Float(name string, fallback ...float64) float64说明:
返回指定环境变量的浮点数值。如果不存在、为空或转换失败,返回默认值。
示例:
rate := env.Float("TAX_RATE", 0.08)ratio := env.Float("COMPRESSION_RATIO", 1.0)Bool - 获取布尔值
func Bool(name string, fallback ...bool) bool说明:
返回指定环境变量的布尔值。支持的值:
true: “1”, “t”, “T”, “true”, “TRUE”, “True”false: “0”, “f”, “F”, “false”, “FALSE”, “False”
示例:
debug := env.Bool("DEBUG", false)verbose := env.Bool("VERBOSE", true)Duration - 获取时间间隔值
func Duration(name string, fallback ...time.Duration) time.Duration说明:
返回指定环境变量的时间间隔值。支持 Go 标准的时间格式(如 “1h30m”)或整数(视为纳秒)。
示例:
// .env 文件// TIMEOUT=30s// INTERVAL=5mtimeout := env.Duration("TIMEOUT", 10*time.Second)interval := env.Duration("INTERVAL", 1*time.Minute)Bytes - 获取字节切片值
func Bytes(name string, fallback ...[]byte) []byte说明:
返回指定环境变量的字节切片值。
示例:
data := env.Bytes("BINARY_DATA")key := env.Bytes("SECRET_KEY", []byte("default-key"))List - 获取字符串列表
func List(name string, fallback ...[]string) []string说明:
返回指定环境变量的字符串列表。值使用英文逗号分割,每个元素会自动 trim 空格。
示例:
// .env 文件// ALLOWED_ORIGINS=http://localhost:3000,https://example.com,https://api.example.com// TAGS=go, web, apiorigins := env.List("ALLOWED_ORIGINS")// []string{"http://localhost:3000", "https://example.com", "https://api.example.com"}tags := env.List("TAGS")// []string{"go", "web", "api"} (自动 trim 空格)// 使用默认值hosts := env.List("REDIS_HOSTS", []string{"localhost:6379"})3. 批量查询函数
Map - 获取相同前缀的所有变量
func Map(prefix string) map[string]string说明:
将具有相同前缀的环境变量聚合成 map 返回。返回的 key 会去掉前缀部分。
示例:
// .env 文件// DB_HOST=localhost// DB_PORT=5432// DB_NAME=mydb// DB_USER=admindbConfig := env.Map("DB_")// map[string]string{// "HOST": "localhost",// "PORT": "5432",// "NAME": "mydb",// "USER": "admin",// }Where - 自定义过滤查询
func Where(filter func(name, value string) bool) map[string]string说明:
返回通过自定义过滤函数筛选后的环境变量。
示例:
// 获取所有以 API_ 开头的变量apiVars := env.Where(func(name, value string) bool { return strings.HasPrefix(name, "API_")})// 获取所有值为 "true" 的变量trueVars := env.Where(func(name, value string) bool { return value == "true"})// 获取所有非空变量nonEmpty := env.Where(func(name, value string) bool { return value != ""})All - 获取所有环境变量
func All() map[string]string说明:
返回所有环境变量(包括系统环境变量和 .env 文件中的变量)。
示例:
allVars := env.All()for name, value := range allVars { fmt.Printf("%s=%s\n", name, value)}4. 结构体填充
Fill - 填充结构体
func Fill(structure any) error说明:
使用环境变量自动填充结构体字段。通过 env 标签指定对应的环境变量名。
示例:
// .env 文件// APP_NAME=MyApp// APP_PORT=8080// APP_DEBUG=true// DB_HOST=localhost// DB_PORT=5432type Config struct { AppName string `env:"APP_NAME"` Port int `env:"APP_PORT"` Debug bool `env:"APP_DEBUG"` Database struct { Host string `env:"DB_HOST"` Port int `env:"DB_PORT"` }}var cfg Configif err := env.Fill(&cfg); err != nil { log.Fatal(err)}fmt.Println(cfg.AppName) // MyAppfmt.Println(cfg.Port) // 8080fmt.Println(cfg.Debug) // true支持的类型:
- 基本类型:
string,int,int8,int16,int32,int64,uint,uint8,uint16,uint32,uint64,float32,float64,bool - 时间类型:
time.Time,time.Duration - 切片类型:
[]int,[]string等 - 嵌套结构体
注意事项:
- 必须传入结构体指针
- 嵌套结构体会递归填充
- 字段必须是导出的(首字母大写)
- 不支持的类型会返回错误
5. 分组查询 - Signed
Signed - 创建分组查询器
func Signed(prefix, category string) Signer说明:
创建一个分组查询器,用于操作相同前缀但需要区分不同场景的环境变量。
查询策略:
采用两级查找,带回退机制:
- 首先查找:
PREFIX_CATEGORY_KEY - 如果未找到,回退到:
PREFIX_KEY
这样可以在前缀级别定义通用配置,在分类级别覆盖特定配置。
示例:
// .env 文件// CACHE_DRIVER=redis// CACHE_DATABASE=1// CACHE_SCOPE=app:// CACHE_BOOK_DATABASE=10// CACHE_BOOK_SCOPE=app:books:// CACHE_USER_DATABASE=11// CACHE_USER_SCOPE=app:users:// 获取 BOOK 分类的缓存配置bookCache := env.Signed("CACHE", "BOOK")bookCache.String("DRIVER") // "redis" (回退到 CACHE_DRIVER)bookCache.Int("DATABASE") // 10 (来自 CACHE_BOOK_DATABASE)bookCache.String("SCOPE") // "app:books:" (来自 CACHE_BOOK_SCOPE)// 获取 USER 分类的缓存配置userCache := env.Signed("CACHE", "USER")userCache.String("DRIVER") // "redis" (回退到 CACHE_DRIVER)userCache.Int("DATABASE") // 11 (来自 CACHE_USER_DATABASE)userCache.String("SCOPE") // "app:users:" (来自 CACHE_USER_SCOPE)// 获取默认缓存配置(不指定分类)defaultCache := env.Signed("CACHE", "")defaultCache.String("DRIVER") // "redis"defaultCache.Int("DATABASE") // 1defaultCache.String("SCOPE") // "app:"Signer 接口方法:
Signer 接口提供了与全局函数相同的查询方法:
Lookup(key string) (string, bool)Exists(key string) boolString(key string, fallback ...string) stringBytes(key string, fallback ...[]byte) []byteInt(key string, fallback ...int) intDuration(key string, fallback ...time.Duration) time.DurationBool(key string, fallback ...bool) boolList(key string, fallback ...[]string) []stringMap(prefix string) map[string]stringWhere(filter func(name, value string) bool) map[string]stringFill(structure any) error
使用场景:
适用于需要为不同模块、不同环境、不同租户配置相似但有差异的环境变量:
// 多租户配置tenant1DB := env.Signed("DB", "TENANT1")tenant2DB := env.Signed("DB", "TENANT2")// 多服务配置authService := env.Signed("SERVICE", "AUTH")apiService := env.Signed("SERVICE", "API")// 多环境缓存prodCache := env.Signed("CACHE", "PROD")devCache := env.Signed("CACHE", "DEV")6. 辅助函数
Path - 获取相对于初始化目录的路径
func Path(path ...string) string说明:
返回基于初始化目录的绝对路径。
示例:
// 假设初始化目录为 /appenv.Init("/app")env.Path() // "/app"env.Path("config") // "/app/config"env.Path("logs", "app.log") // "/app/logs/app.log"Is - 检查应用环境
func Is(env ...string) bool说明:
检查 APP_ENV 环境变量是否匹配任何给定的值。
示例:
// .env 文件// APP_ENV=developmentif env.Is("development", "dev") { // 开发环境 log.Println("Running in development mode")}if env.Is("production", "prod") { // 生产环境} else { // 非生产环境}Updates - 更新环境变量
func Updates(data map[string]string) bool说明:
批量更新环境变量。返回 true 表示成功,false 表示失败(如已锁定)。
示例:
// 动态设置环境变量success := env.Updates(map[string]string{ "FEATURE_FLAG_A": "true", "FEATURE_FLAG_B": "false",})if !success { log.Println("Failed to update environment")}注意事项:
- 调用
Lock()后无法使用 - 不是线程安全的,仅在初始化阶段使用
使用场景
1. 多环境配置
// 项目结构// .env # 默认配置// .env.local # 本地覆盖(不提交到 git)// .env.development # 开发环境// .env.development.local// .env.production # 生产环境// .env.production.local// main.gofunc main() { // 自动根据 APP_ENV 加载对应配置 if err := env.Init(); err != nil { log.Fatal(err) } env.Lock() // 根据环境执行不同逻辑 if env.Is("development") { // 开发环境配置 gin.SetMode(gin.DebugMode) } else if env.Is("production") { // 生产环境配置 gin.SetMode(gin.ReleaseMode) }}2. 数据库配置管理
type DatabaseConfig struct { Host string `env:"DB_HOST"` Port int `env:"DB_PORT"` Database string `env:"DB_NAME"` Username string `env:"DB_USER"` Password string `env:"DB_PASSWORD"` MaxConns int `env:"DB_MAX_CONNS"` SSLMode string `env:"DB_SSL_MODE"`}func NewDatabaseConfig() (*DatabaseConfig, error) { cfg := &DatabaseConfig{} if err := env.Fill(cfg); err != nil { return nil, err } return cfg, nil}func main() { env.Init() env.Lock() dbCfg, err := NewDatabaseConfig() if err != nil { log.Fatal(err) } dsn := fmt.Sprintf("host=%s port=%d dbname=%s user=%s password=%s sslmode=%s", dbCfg.Host, dbCfg.Port, dbCfg.Database, dbCfg.Username, dbCfg.Password, dbCfg.SSLMode)}3. 多租户/多实例配置
// .env 文件// REDIS_HOST=localhost// REDIS_PORT=6379// REDIS_SESSION_DATABASE=0// REDIS_SESSION_PREFIX=session:// REDIS_CACHE_DATABASE=1// REDIS_CACHE_PREFIX=cache:// REDIS_QUEUE_DATABASE=2// REDIS_QUEUE_PREFIX=queue:// 为不同用途创建不同的 Redis 客户端func setupRedis() { env.Init() env.Lock() // Session Redis sessionRedis := env.Signed("REDIS", "SESSION") sessionClient := redis.NewClient(&redis.Options{ Addr: fmt.Sprintf("%s:%d", sessionRedis.String("HOST", "localhost"), sessionRedis.Int("PORT", 6379)), DB: sessionRedis.Int("DATABASE", 0), }) // Cache Redis cacheRedis := env.Signed("REDIS", "CACHE") cacheClient := redis.NewClient(&redis.Options{ Addr: fmt.Sprintf("%s:%d", cacheRedis.String("HOST", "localhost"), cacheRedis.Int("PORT", 6379)), DB: cacheRedis.Int("DATABASE", 1), }) // Queue Redis queueRedis := env.Signed("REDIS", "QUEUE") queueClient := redis.NewClient(&redis.Options{ Addr: fmt.Sprintf("%s:%d", queueRedis.String("HOST", "localhost"), queueRedis.Int("PORT", 6379)), DB: queueRedis.Int("DATABASE", 2), })}4. 特性开关(Feature Flags)
// .env 文件// FEATURE_NEW_UI=true// FEATURE_BETA_API=false// FEATURE_ANALYTICS=truetype Features struct { NewUI bool `env:"FEATURE_NEW_UI"` BetaAPI bool `env:"FEATURE_BETA_API"` Analytics bool `env:"FEATURE_ANALYTICS"`}func main() { env.Init() env.Lock() features := &Features{} env.Fill(features) if features.NewUI { // 启用新 UI } if features.BetaAPI { // 启用 Beta API }}5. 服务发现配置
// .env 文件// SERVICES=auth,api,notification,payment// SERVICE_AUTH_URL=http://auth:8001// SERVICE_API_URL=http://api:8002// SERVICE_NOTIFICATION_URL=http://notification:8003// SERVICE_PAYMENT_URL=http://payment:8004func loadServiceURLs() map[string]string { env.Init() env.Lock() services := env.List("SERVICES") urls := make(map[string]string) for _, service := range services { signer := env.Signed("SERVICE", strings.ToUpper(service)) if url, exists := signer.Lookup("URL"); exists { urls[service] = url } } return urls}// 使用serviceURLs := loadServiceURLs()authURL := serviceURLs["auth"] // http://auth:8001apiURL := serviceURLs["api"] // http://api:8002线程安全说明
设计模型:“一次初始化,多次读取”
env 库采用了明确的两阶段设计:
初始化阶段(单线程):
- 调用
Init(),InitWithDir(),Load(),Updates() - 必须在启动任何 goroutine 之前完成
- 这些函数不是线程安全的
运行时阶段(多线程):
- 调用
Lookup(),String(),Int()等读取函数 - 所有读取操作都是线程安全的
- 多个 goroutine 可以并发读取
正确用法
func main() { // ✓ 正确:启动时单线程初始化 if err := env.Init(); err != nil { log.Fatal(err) } // ✓ 最佳实践:锁定防止意外修改 env.Lock() // ✓ 正确:读取操作线程安全 go func() { cache := env.Signed("CACHE", "BOOK") driver := cache.String("DRIVER") // 安全 }() go func() { port := env.Int("PORT", 8080) // 安全 }()}错误用法
func main() { // ✗ 错误:并发调用 Init 会导致数据竞争 go env.Init() // 不要这样做! go env.Init() // 不要这样做! // ✗ 错误:运行时修改环境变量会导致数据竞争 go func() { env.Load(".env.runtime") // 不要在运行时这样做! }()}为什么不需要锁?
- 初始化阶段:单线程执行,无需加锁
- 运行时阶段:只读访问,Go 的切片读取本身就是线程安全的
- 环境数据:初始化完成后永不改变
Lock() 函数的作用是在运行时强制执行只读约定,防止意外的写操作。
API 参考
全局函数
| 函数 | 说明 | 线程安全 |
|---|---|---|
Init(root ...string) error | 初始化环境变量 | 否 |
InitWithDir(dir string) error | 从指定目录初始化 | 否 |
Load(filenames ...string) error | 加载指定文件 | 否 |
Lock() | 锁定环境变量 | 是 |
Signed(prefix, category string) Signer | 创建分组查询器 | 是 |
Path(path ...string) string | 获取相对路径 | 是 |
Is(env ...string) bool | 检查应用环境 | 是 |
Updates(data map[string]string) bool | 更新环境变量 | 否 |
查询函数(线程安全)
| 函数 | 说明 |
|---|---|
Lookup(name string) (string, bool) | 查询环境变量 |
Exists(name string) bool | 检查是否存在 |
String(name string, fallback ...string) string | 获取字符串值 |
Bytes(name string, fallback ...[]byte) []byte | 获取字节切片 |
Int(name string, fallback ...int) int | 获取整数值 |
Float(name string, fallback ...float64) float64 | 获取浮点数值 |
Bool(name string, fallback ...bool) bool | 获取布尔值 |
Duration(name string, fallback ...time.Duration) time.Duration | 获取时间间隔 |
List(name string, fallback ...[]string) []string | 获取字符串列表 |
Map(prefix string) map[string]string | 获取相同前缀的所有变量 |
Where(filter func(name, value string) bool) map[string]string | 自定义过滤查询 |
Fill(structure any) error | 填充结构体 |
All() map[string]string | 获取所有环境变量 |
Signer 接口
Signer 提供与全局函数相同的查询方法,但会自动添加前缀和分类。
注意事项
1. 初始化顺序
环境变量的加载顺序会影响最终值(后加载的覆盖先加载的):
系统环境变量 ↓.env ↓ (覆盖).env.local ↓ (覆盖).env.{APP_ENV} ↓ (覆盖).env.{APP_ENV}.local2. .gitignore 配置
建议的 .gitignore 配置:
# 本地配置不提交.env.local.env.*.local# 可选:也可以不提交 .env.env提交 .env 作为模板,使用 .env.local 存储本地敏感配置。
3. 环境变量命名规范
建议的命名规范:
- 使用大写字母和下划线
- 使用前缀分组相关配置(如
DB_,CACHE_,REDIS_) - 使用中间部分表示分类(如
CACHE_BOOK_,CACHE_USER_) - 使用后缀表示具体配置项(如
_HOST,_PORT,_DATABASE)
示例:
# 好的命名DB_HOST=localhostDB_PORT=5432CACHE_REDIS_HOST=localhostCACHE_REDIS_PORT=6379# 不推荐dbhost=localhost # 小写database-port=5432 # 使用连字符redis.host=localhost # 使用点号4. 类型转换失败
当类型转换失败时,会返回默认值:
// .env 文件// PORT=invalidport := env.Int("PORT", 8080) // 返回 8080(转换失败,使用默认值)如果需要知道转换是否成功,使用 Lookup 配合手动转换:
if value, exists := env.Lookup("PORT"); exists { if port, err := strconv.Atoi(value); err == nil { // 转换成功 } else { // 转换失败 log.Printf("Invalid PORT value: %s", value) }}5. 敏感信息保护
不要将敏感信息(密码、密钥等)提交到版本控制系统:
// 使用 .env.local 存储敏感信息// .env.local(不提交到 git)DB_PASSWORD=super_secret_passwordAPI_SECRET_KEY=your_secret_key_here// .env(可以提交,提供模板)DB_HOST=localhostDB_PORT=5432DB_NAME=mydbDB_USER=admin# DB_PASSWORD= # 在 .env.local 中设置6. 默认值的使用
合理使用默认值可以简化配置:
// 开发环境的合理默认值port := env.Int("PORT", 8080)debug := env.Bool("DEBUG", true) // 开发环境默认开启timeout := env.Duration("TIMEOUT", 30*time.Second)// 这样 .env 文件可以只配置需要修改的值7. 结构体填充的限制
Fill() 函数的限制:
// ✓ 支持type Config struct { Port int `env:"PORT"` // 导出字段 + env 标签}// ✗ 不支持type Config struct { port int `env:"PORT"` // 未导出字段 Port int // 缺少 env 标签}8. Signed 的查找顺序
理解 Signed 的回退机制:
// 环境变量:// CACHE_DRIVER=redis// CACHE_BOOK_DATABASE=10cache := env.Signed("CACHE", "BOOK")// 查找 DRIVER// 1. 尝试 CACHE_BOOK_DRIVER (不存在)// 2. 回退到 CACHE_DRIVER (找到: "redis")// 查找 DATABASE// 1. 尝试 CACHE_BOOK_DATABASE (找到: 10)// 2. 不需要回退最佳实践
1. 标准初始化流程
func main() { // 1. 初始化环境变量 if err := env.Init(); err != nil { log.Fatalf("Failed to initialize env: %v", err) } // 2. 锁定,防止运行时修改 env.Lock() // 3. 加载配置 cfg := loadConfig() // 4. 启动应用 startApp(cfg)}func loadConfig() *Config { cfg := &Config{} if err := env.Fill(cfg); err != nil { log.Fatalf("Failed to load config: %v", err) } return cfg}2. 配置结构化
// 将相关配置组织到结构体type AppConfig struct { Server ServerConfig Database DatabaseConfig Redis RedisConfig Logger LoggerConfig}type ServerConfig struct { Port int `env:"SERVER_PORT"` Host string `env:"SERVER_HOST"` Timeout time.Duration `env:"SERVER_TIMEOUT"`}type DatabaseConfig struct { Host string `env:"DB_HOST"` Port int `env:"DB_PORT"` Database string `env:"DB_NAME"` Username string `env:"DB_USER"` Password string `env:"DB_PASSWORD"`}func LoadAppConfig() (*AppConfig, error) { cfg := &AppConfig{} if err := env.Fill(cfg); err != nil { return nil, err } return cfg, nil}3. 使用 Signed 管理多实例
// 为不同的服务实例使用不同的配置func setupServices() { authService := setupService("AUTH") apiService := setupService("API") notifyService := setupService("NOTIFICATION")}func setupService(name string) *Service { cfg := env.Signed("SERVICE", name) return &Service{ URL: cfg.String("URL"), Timeout: cfg.Duration("TIMEOUT", 30*time.Second), APIKey: cfg.String("API_KEY"), }}4. 提供配置模板
在项目中提供 .env.example 文件作为配置模板:
# .env.example - 配置模板(提交到 git)# 应用配置APP_ENV=developmentAPP_NAME=MyAppAPP_PORT=8080APP_DEBUG=true# 数据库配置(填写实际值)DB_HOST=localhostDB_PORT=5432DB_NAME=DB_USER=DB_PASSWORD=# Redis 配置REDIS_HOST=localhostREDIS_PORT=6379REDIS_DATABASE=0用户复制并重命名为 .env,然后填写实际值。
相关链接
- GitHub 仓库
- godotenv - .env 文件解析库
- go-slim.dev/cast - 类型转换库