Slim

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 文件所在目录,不指定则使用当前程序的运行目录

加载顺序

  1. 系统环境变量
  2. .env 文件
  3. .env.local 文件(优先级更高,可覆盖 .env
  4. .env.{APP_ENV} 文件(根据 APP_ENV 变量)
  5. .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()

说明

锁定全局环境变量,防止后续修改。调用后任何写操作(InitLoadUpdates)都会失败。

最佳实践

在初始化完成后立即调用 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 存在且非空时才为 true

String - 获取字符串值

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

说明

创建一个分组查询器,用于操作相同前缀但需要区分不同场景的环境变量。

查询策略

采用两级查找,带回退机制:

  1. 首先查找:PREFIX_CATEGORY_KEY
  2. 如果未找到,回退到: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) bool
  • String(key string, fallback ...string) string
  • Bytes(key string, fallback ...[]byte) []byte
  • Int(key string, fallback ...int) int
  • Duration(key string, fallback ...time.Duration) time.Duration
  • Bool(key string, fallback ...bool) bool
  • List(key string, fallback ...[]string) []string
  • Map(prefix string) map[string]string
  • Where(filter func(name, value string) bool) map[string]string
  • Fill(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}.local

2. .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,然后填写实际值。


相关链接

切换 选择 esc 关闭搜索