Skip to content

快速开始

5 分钟上手 env 库,从安装到实际使用。

安装

bash
go get github.com/cybergodev/env

要求

Go 1.25+

创建 .env 文件

在项目根目录创建 .env 文件:

bash
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=secret

# 应用配置
DEBUG=true
APP_NAME=myapp
LOG_LEVEL=info

# 多值(逗号分隔)
ALLOWED_HOSTS=localhost,example.com,api.example.com

最简用法

go
package main

import (
    "fmt"
    "github.com/cybergodev/env"
)

func main() {
    // 加载 .env 文件并应用到系统环境
    if err := env.Load(".env"); err != nil {
        panic(err)
    }

    // 获取环境变量
    host := env.GetString("DB_HOST", "localhost")
    port := env.GetInt("DB_PORT", 5432)

    fmt.Printf("Server: %s:%d\n", host, port)
}

读取值 - 所有类型

基本类型

go
// === 带默认值 ===

// 字符串 - 未找到时返回默认值 "localhost"
host := env.GetString("HOST", "localhost")

// 整数 (int64) - 未找到时返回默认值 8080
port := env.GetInt("PORT", 8080)

// 布尔值 - 未找到时返回默认值 false
debug := env.GetBool("DEBUG", false)

// 时间间隔 - 未找到时返回默认值 30s
timeout := env.GetDuration("TIMEOUT", 30*time.Second)


// === 不带默认值 ===

// 字符串 - 未找到时返回空字符串 ""
host := env.GetString("HOST")

// 整数 (int64) - 未找到时返回 0
port := env.GetInt("PORT")

// 布尔值 - 未找到时返回 false
debug := env.GetBool("DEBUG")

// 时间间隔 - 未找到时返回 0
timeout := env.GetDuration("TIMEOUT")

键名解析

库支持多种键名访问方式:

go
// JSON: {"app": {"name": "myapp"}}
// 存储为:APP_NAME=myapp

// 以下方式都能访问到该值
name := env.GetString("APP_NAME")      // 扁平化键名(推荐)
name := env.GetString("app.name")      // 点号路径(自动转换)
name := env.GetString("APP.NAME")      // 大写点号路径

解析规则:

  1. 精确匹配:优先查找精确键名 KEY
  2. 大写转换:小写键名尝试大写版本 keyKEY
  3. 路径解析:点号路径转换为下划线 app.nameAPP_NAME

布尔值支持

GetBool 支持以下值(不区分大小写):

真值假值
true, 1, yes, on, enabledfalse, 0, no, off, disabled

切片类型

go
// 字符串切片
hosts := env.GetSlice[string]("HOSTS", []string{"localhost"})

// 整数切片(支持 int, int64, uint, uint64)
ports := env.GetSlice[int64]("PORTS", []int64{80, 443})
portsInt := env.GetSlice[int]("PORTS")  // 也支持 int 类型

// 浮点数切片
rates := env.GetSlice[float64]("RATES", []float64{0.1, 0.2})

// 布尔切片
flags := env.GetSlice[bool]("FLAGS", []bool{true, false})

// Duration 切片
timeouts := env.GetSlice[time.Duration]("TIMEOUTS")

解析顺序:

  1. 优先查找索引键 KEY_0, KEY_1, KEY_2...
  2. 若无索引键,则按逗号分隔解析 KEY 的值
go
// 方式一:索引键(推荐)
// HOSTS_0=localhost
// HOSTS_1=example.com
hosts := env.GetSlice[string]("HOSTS")  // ["localhost", "example.com"]

// 方式二:逗号分隔
// PORTS=80,443,8080
ports := env.GetSlice[int64]("PORTS")  // [80, 443, 8080]

检查与查找

go
// 检查键是否存在
value, exists := env.Lookup("API_KEY")
if !exists {
    // 键不存在
}

// 获取所有键
keys := env.Keys()

// 获取所有键值对
all := env.All()

// 获取变量数量
count := env.Len()

安全值

go
secret := env.GetSecure("API_KEY")
if secret != nil {
    defer secret.Release()

    // 获取原始值(仅在需要明文时调用,如加解密、API 调用)
    value := secret.Reveal()

    // 日志使用掩码(防止泄露)
    log.Printf("API Key: %s", secret.Masked())  // 输出:[SECURE:32 bytes]
}

结构体映射

使用标签将环境变量映射到结构体:

go
package main

import (
    "fmt"
    "time"

    "github.com/cybergodev/env"
)

type Config struct {
    Host     string        `env:"DB_HOST" envDefault:"localhost"`
    Port     int64         `env:"DB_PORT" envDefault:"5432"`
    Password string        `env:"DB_PASSWORD"`
    Debug    bool          `env:"DEBUG" envDefault:"false"`
    Timeout  time.Duration `env:"TIMEOUT" envDefault:"30s"`
    Hosts    []string      `env:"ALLOWED_HOSTS"`
}

func main() {
    env.Load(".env")

    var cfg Config
    if err := env.ParseInto(&cfg); err != nil {
        panic(err)
    }

    fmt.Printf("%+v\n", cfg)
}
详见

结构体映射 指南。

配置预设

库提供四种预设配置,适用于不同场景:

预设用途特点
DefaultConfig()通用场景安全默认值,适合大多数情况
DevelopmentConfig()开发环境宽松限制,允许覆盖
TestingConfig()测试环境紧凑限制,允许覆盖,适合单元测试
ProductionConfig()生产环境严格验证 + 审计日志
go
// 开发环境 - 宽松限制
cfg := env.DevelopmentConfig()

// 测试环境 - 紧凑限制
cfg := env.TestingConfig()

// 生产环境 - 严格验证 + 审计日志
cfg := env.ProductionConfig()

预设详细对比

功能DefaultDevelopmentTestingProduction
覆盖已存在变量
文件不存在时报错
审计日志
YAML 语法
文件大小限制2MB10MB64KB64KB
最大变量数5005005050
禁止键检查
值验证

选择建议

  • 开发环境:使用 DevelopmentConfig(),宽松限制便于快速迭代
  • 测试环境:使用 TestingConfig(),允许覆盖便于测试隔离
  • 生产环境:使用 ProductionConfig(),启用审计和严格验证

多环境配置

按环境加载

go
// 根据环境确定配置文件
goEnv := os.Getenv("GO_ENV")
if goEnv == "" {
    goEnv = "development"
}

// 单次调用加载所有配置文件(按顺序,后加载的覆盖先加载的)
env.Load(".env", ".env."+goEnv, ".env.local")

使用 Loader 实例

需要更多控制时,使用 Loader 实例:

go
package main

import (
    "fmt"
    "github.com/cybergodev/env"
)

func main() {
    // 创建配置
    cfg := env.ProductionConfig()
    cfg.RequiredKeys = []string{"DB_HOST", "API_KEY"}

    // 创建加载器
    loader, err := env.New(cfg)
    if err != nil {
        panic(err)
    }
    defer loader.Close()

    // 加载文件(按顺序,后加载的覆盖先加载的)
    if err := loader.LoadFiles(".env", ".env.production"); err != nil {
        panic(err)
    }

    // 验证必需键
    if err := loader.Validate(); err != nil {
        panic(err)
    }

    // 使用
    host := loader.GetString("DB_HOST")
    fmt.Println("Host:", host)
}

多文件与多格式

多文件加载

按顺序加载,后加载的覆盖先加载的:

go
env.Load(".env", "config.json", "config.yaml")
go
loader.LoadFiles(".env", ".env.local")

多格式支持

自动检测文件格式:

go
loader.LoadFiles("config.env", "settings.json", "secrets.yaml")
支持的格式
格式扩展名检测方式
.env.env文件扩展名
JSON.json文件扩展名
YAML.yaml, .yml文件扩展名

错误处理

go
import "errors"

err := loader.LoadFiles(".env")
if err != nil {
    switch {
    case errors.Is(err, env.ErrFileNotFound):
        // 文件不存在
    case errors.Is(err, env.ErrFileTooLarge):
        // 文件过大
    case errors.Is(err, env.ErrSecurityViolation):
        // 禁止键(实际返回 *SecurityError)
    default:
        // 其他错误
    }

    // 键格式非法:实际返回 *ValidationError,Field=="key"
    var valErr *env.ValidationError
    if errors.As(err, &valErr) && valErr.Field == "key" {
        // 无效键格式
    }
}
获取详细错误信息
go
// 解析错误详情
var parseErr *env.ParseError
if errors.As(err, &parseErr) {
    fmt.Printf("文件 %s%d 行: %v\n", parseErr.File, parseErr.Line, parseErr.Err)
}

// 文件错误详情
var fileErr *env.FileError
if errors.As(err, &fileErr) {
    fmt.Printf("文件 %s 操作 %s 失败: %v\n", fileErr.Path, fileErr.Op, fileErr.Err)
}

// 安全错误详情
var secErr *env.SecurityError
if errors.As(err, &secErr) {
    fmt.Printf("安全错误: %s - %s\n", secErr.Action, secErr.Reason)
}

下一步

深入学习

API 参考

安全