Skip to content

Loader API

Loader 类型的完整方法参考。Loader 是 env 库的核心类型,提供环境变量的加载、存储和访问功能。

线程安全

Loader 的所有方法都是线程安全的,可在多个 goroutine 中并发调用。

类型定义

go
type Loader struct {
    // 包含私有字段
}

// 编译时检查接口实现
var _ EnvLoader = (*Loader)(nil)
var _ io.Closer = (*Loader)(nil)

创建

New

go
func New(cfg ...Config) (*Loader, error)

创建新的加载器实例。

参数:

  • cfg - 可选配置选项。不提供或传入零值 Config 时,自动使用 DefaultConfig()

返回:

  • *Loader - 加载器实例
  • error - 配置验证错误

行为:

  • 验证配置有效性
  • 创建内部组件(验证器、审计器、展开器)
  • 如果 cfg.Filenames 非空,自动加载文件
  • 如果 cfg.AutoApply 为 true,自动应用到系统环境
go
// 使用默认配置
loader, err := env.New()

// 使用自定义配置
cfg := env.DefaultConfig()
cfg.Filenames = []string{".env"}
cfg.AutoApply = true
loader, err := env.New(cfg)

if err != nil {
    panic(err)
}
defer loader.Close()

文件加载

LoadFiles

go
func (l *Loader) LoadFiles(filenames ...string) error

加载一个或多个配置文件。

参数:

  • filenames - 文件路径列表,为空时默认加载 .env

返回:

  • error - 加载错误

行为:

  • 按顺序加载,后加载的覆盖先加载的(受 OverwriteExisting 配置控制)
  • 自动检测文件格式(.env、JSON、YAML)
  • 根据 FailOnMissingFile 配置决定文件不存在时的行为
  • 如果 AutoApply 为 true,加载后自动应用
go
// 加载默认 .env 文件
err := loader.LoadFiles()

// 加载指定文件
err := loader.LoadFiles(".env", ".env.local")

// 混合格式
err := loader.LoadFiles("config.env", "settings.json", "secrets.yaml")

错误类型:

  • ErrFileNotFound - 文件不存在(当 FailOnMissingFile=true
  • ErrFileTooLarge - 文件超过大小限制
  • ErrClosed - 加载器已关闭
  • *ParseError - 解析错误
  • *JSONError - JSON 解析错误
  • *YAMLError - YAML 解析错误
  • *SecurityError - 文件路径安全校验失败(如路径穿越攻击)

格式检测规则:

扩展名格式
.envFormatEnv
.jsonFormatJSON
.yaml, .ymlFormatYAML
其他FormatAuto(使用 .env 解析器)

获取值

键名解析

所有获取方法都支持智能键名解析:

输入键名解析结果
"DATABASE_HOST""DATABASE_HOST"(精确匹配)
"database.host""DATABASE_HOST"(点号转下划线)
"app.name""APP_NAME"(大写 + 下划线)
"servers.0.host""SERVERS_0_HOST"(数组索引)

解析顺序:

  1. 精确匹配 - 直接查找键名
  2. 大写转换 - 简单键尝试大写版本
  3. 路径解析 - 点号路径转换为下划线格式
  4. 索引回退 - 索引访问时回退到逗号分隔值

GetString

go
func (l *Loader) GetString(key string, defaultValue ...string) string

获取字符串值。支持点号路径解析。

参数:

  • key - 键名(支持精确匹配、大写转换、点号路径)
  • defaultValue - 可选默认值

返回:

  • string - 值或默认值(未找到且无默认值时返回空字符串)
go
// 基本用法
host := loader.GetString("HOST", "localhost")

// 点号路径访问(JSON/YAML 嵌套结构)
dbHost := loader.GetString("database.host", "localhost")
appName := loader.GetString("app.name")

// 无默认值时返回空字符串
value := loader.GetString("NON_EXISTENT")  // ""

GetInt

go
func (l *Loader) GetInt(key string, defaultValue ...int64) int64

获取整数值。支持点号路径解析。

参数:

  • key - 键名(支持点号路径)
  • defaultValue - 可选默认值,类型为 int64

返回:

  • int64 - 值或默认值(未找到且无默认值时返回 0)
go
port := loader.GetInt("PORT", 8080)
maxConn := loader.GetInt("database.max_connections", 10)

// 无默认值时返回 0
value := loader.GetInt("NON_EXISTENT")  // 0

GetBool

go
func (l *Loader) GetBool(key string, defaultValue ...bool) bool

获取布尔值。支持点号路径解析。

参数:

  • key - 键名(支持点号路径)
  • defaultValue - 可选默认值

返回:

  • bool - 值或默认值(未找到且无默认值时返回 false)

支持的值:

  • 真值:true, 1, yes, on, enabled
  • 假值:false, 0, no, off, disabled
go
debug := loader.GetBool("DEBUG", false)
cacheEnabled := loader.GetBool("cache.enabled", true)

// 无默认值时返回 false
value := loader.GetBool("NON_EXISTENT")  // false

GetUint64

go
func (l *Loader) GetUint64(key string, defaultValue ...uint64) uint64

获取无符号整数值。支持点号路径解析。

参数:

  • key - 键名(支持点号路径)
  • defaultValue - 可选默认值,类型为 uint64

返回:

  • uint64 - 值或默认值(未找到且无默认值时返回 0)
go
port := loader.GetUint64("PORT", 8080)
maxSize := loader.GetUint64("MAX_SIZE", 1024)

// 无默认值时返回 0
value := loader.GetUint64("NON_EXISTENT")  // 0

GetFloat64

go
func (l *Loader) GetFloat64(key string, defaultValue ...float64) float64

获取浮点数值。支持点号路径解析。

参数:

  • key - 键名(支持点号路径)
  • defaultValue - 可选默认值,类型为 float64

返回:

  • float64 - 值或默认值(未找到且无默认值时返回 0)
go
rate := loader.GetFloat64("RATE", 0.5)
threshold := loader.GetFloat64("THRESHOLD")

// 无默认值时返回 0
value := loader.GetFloat64("NON_EXISTENT")  // 0

GetDuration

go
func (l *Loader) GetDuration(key string, defaultValue ...time.Duration) time.Duration

获取时间间隔值。支持点号路径解析。

参数:

  • key - 键名(支持点号路径)
  • defaultValue - 可选默认值

返回:

  • time.Duration - 值或默认值(未找到且无默认值时返回 0)

支持格式: ns, us, ms, s, m, h(如 30s, 5m, 1h30m

go
timeout := loader.GetDuration("TIMEOUT", 30*time.Second)
ttl := loader.GetDuration("cache.ttl", 5*time.Minute)

// 无默认值时返回 0
value := loader.GetDuration("NON_EXISTENT")  // 0

GetSecure

go
func (l *Loader) GetSecure(key string) *SecureValue

获取安全值(敏感数据保护)。

参数:

  • key - 键名

返回:

  • *SecureValue - 安全值的防御性副本,调用者负责释放;键不存在或加载器关闭时返回 nil
go
secret := loader.GetSecure("API_SECRET")
if secret != nil {
    defer secret.Release()

    value := secret.Reveal()   // 明文值
    masked := secret.Masked()  // [SECURE:32 bytes]
}

重要

使用后必须调用 Release()Close() 释放资源。

防御性副本

GetSecure 返回的是原始值的副本,独立于父 Loader。调用者负责调用 Release()Close() 释放。

详见

SecureValue API 获取完整文档。


获取切片值

Loader 没有提供切片获取方法(Go 不支持泛型方法)。使用独立的泛型函数 GetSliceFrom[T] 从 Loader 实例获取切片:

go
// 使用独立泛型函数
hosts := env.GetSliceFrom[string](loader, "HOSTS")
ports := env.GetSliceFrom[int64](loader, "PORTS", []int64{80})
portsInt := env.GetSliceFrom[int](loader, "PORTS")  // 也支持 int

支持的类型: string, int, int64, uint, uint64, bool, float64, time.Duration

详见

包函数 - GetSliceFrom 获取完整文档。


Lookup

go
func (l *Loader) Lookup(key string) (string, bool)

检查键是否存在并获取值。支持点号路径解析。

参数:

  • key - 键名(支持点号路径)

返回:

  • string - 值(首尾空白已移除)
  • bool - 是否存在
go
value, exists := loader.Lookup("API_KEY")
if !exists {
    // 键不存在
}

// 点号路径
if value, exists := loader.Lookup("database.host"); exists {
    fmt.Println(value)
}

// 索引访问(回退到逗号分隔值)
// HOSTS=localhost,example.com
if value, exists := loader.Lookup("hosts.0"); exists {
    fmt.Println(value)  // "localhost"
}

设置和删除

Set

go
func (l *Loader) Set(key, value string) error

设置环境变量。

参数:

  • key - 键名
  • value - 值

返回:

  • error - 设置错误

行为:

  • 验证键名有效性
  • 如果 ValidateValues 为 true,验证值安全性
  • 如果 OverwriteExisting 为 false 且键已存在,跳过(返回 nil)
  • 如果 AutoApply 为 true,同时设置到系统环境
go
err := loader.Set("CUSTOM_KEY", "value")
if err != nil {
    // 处理错误
}

错误类型:

  • *ValidationError - 键名格式无效(Field="key")
  • *SecurityError - 键被禁止(可用 errors.Is(err, env.ErrSecurityViolation) 匹配)
  • ErrInvalidValue - 值无效(当 ValidateValues 为 true 时,值包含空字节、控制字符等不安全内容)
  • ErrClosed - 加载器已关闭

Delete

go
func (l *Loader) Delete(key string) error

删除环境变量。

参数:

  • key - 键名

返回:

  • error - 删除错误

行为:

  • 如果变量已应用到系统环境,同时从系统环境删除
go
err := loader.Delete("TEMP_KEY")
if err != nil {
    panic(err)
}

集合操作

Keys

go
func (l *Loader) Keys() []string

获取所有键名。

返回:

  • []string - 键名列表,加载器已关闭返回 nil
go
keys := loader.Keys()
for _, key := range keys {
    fmt.Println(key)
}

All

go
func (l *Loader) All() map[string]string

获取所有键值对。

返回:

  • map[string]string - 键值映射,加载器已关闭返回 nil
go
all := loader.All()
for key, value := range all {
    fmt.Printf("%s=%s\n", key, value)
}

Len

go
func (l *Loader) Len() int

获取变量数量。

返回:

  • int - 变量数量,加载器已关闭返回 0
go
count := loader.Len()
fmt.Printf("已加载 %d 个变量\n", count)

应用到系统

Apply

go
func (l *Loader) Apply() error

将变量应用到系统环境(os.Environ)。

返回:

  • error - 应用错误

行为:

  • 遍历所有加载的变量
  • 根据 OverwriteExisting 配置决定是否覆盖已存在的系统环境变量
  • 应用后可通过 os.Getenv() 访问

错误类型:

  • ErrClosed - 加载器已关闭
  • 包装的 os 错误 - 设置环境变量失败(键名已掩码,错误消息中不暴露敏感键名)
go
err := loader.Apply()
if err != nil {
    panic(err)
}

// 之后 os.Getenv() 也能访问
host := os.Getenv("HOST")

IsApplied

go
func (l *Loader) IsApplied() bool

检查变量是否已应用到系统环境。

返回:

  • bool - 是否已应用
go
if loader.IsApplied() {
    // 变量已应用到 os.Environ
}

状态查询

LoadTime

go
func (l *Loader) LoadTime() time.Time

返回最后一次加载文件的时间。

返回:

  • time.Time - 加载时间,未加载返回零值
go
loadTime := loader.LoadTime()
if !loadTime.IsZero() {
    fmt.Printf("最后加载时间: %v\n", loadTime)
}

Config

go
func (l *Loader) Config() Config

返回加载器的配置。

返回:

  • Config - 配置(应视为只读)

注意

返回的 Config 应被视为只读。修改 KeyPatternAllowedKeysForbiddenKeysRequiredKeys 等字段可能影响加载器行为。如需安全的可变副本,请手动复制所需字段。

go
cfg := loader.Config()
fmt.Printf("最大文件大小:%d\n", cfg.MaxFileSize)

验证与映射

Validate

go
func (l *Loader) Validate() error

验证必需键是否存在。

返回:

  • error - 验证错误

行为:

  • 检查 ValidationConfig.RequiredKeys 中指定的所有键是否存在
go
cfg := env.DefaultConfig()
cfg.RequiredKeys = []string{"DB_HOST", "API_KEY"}

loader, _ := env.New(cfg)
loader.LoadFiles(".env")

if err := loader.Validate(); err != nil {
    // 缺少必需键
    var missingErr *env.ValidationError
    if errors.As(err, &missingErr) {
        fmt.Printf("缺少: %s\n", missingErr.Field)
    }
}

ParseInto

go
func (l *Loader) ParseInto(v any) error

将环境变量映射到结构体。

参数:

  • v - 结构体指针

返回:

  • error - 映射错误

支持的标签:

  • env:"KEY" - 指定环境变量名
  • env:"-" - 忽略此字段
  • envDefault:"value" - 指定默认值

切片字段默认按逗号 , 分隔(分隔符前后空格自动去除),无自定义分隔符标签。

go
type Config struct {
    Host    string   `env:"HOST" envDefault:"localhost"`
    Port    int64    `env:"PORT" envDefault:"8080"`
    Debug   bool     `env:"DEBUG" envDefault:"false"`
    Hosts   []string `env:"HOSTS"`
    Ignored string   `env:"-"`
}

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

资源释放

Close

go
func (l *Loader) Close() error

释放资源并清空存储。

返回:

  • error - 关闭错误

行为:

  • 安全清零所有存储的敏感数据
  • 如果加载器拥有 ComponentFactory,同时关闭工厂
  • 安全关闭,多次调用返回 nil
go
loader, _ := env.New(cfg)
defer loader.Close()

// 使用 loader...

关闭后行为

关闭后所有操作将返回错误或零值:

  • LoadFilesErrClosed
  • GetString → 返回空值
  • SetErrClosed
  • Keys → 返回 nil
  • Len → 返回 0

IsClosed

go
func (l *Loader) IsClosed() bool

检查加载器是否已关闭。

返回:

  • bool - 是否已关闭
go
if loader.IsClosed() {
    // 加载器已关闭
}

完整示例

go
package main

import (
    "errors"
    "fmt"
    "log"
    "os"
    "time"

    "github.com/cybergodev/env"
)

func main() {
    // 创建生产环境配置
    cfg := env.ProductionConfig()
    cfg.RequiredKeys = []string{"DB_HOST", "API_KEY"}
    cfg.AuditHandler = env.NewJSONAuditHandler(os.Stdout)

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

    // 加载文件
    if err := loader.LoadFiles(".env", ".env.production"); err != nil {
        if errors.Is(err, env.ErrFileNotFound) {
            log.Fatal("配置文件不存在")
        }
        log.Fatal(err)
    }

    // 验证必需键
    if err := loader.Validate(); err != nil {
        log.Fatal("缺少必需配置:", err)
    }

    // 读取配置
    host := loader.GetString("DB_HOST")
    port := loader.GetInt("DB_PORT", 5432)
    debug := loader.GetBool("DEBUG", false)
    timeout := loader.GetDuration("TIMEOUT", 30*time.Second)

    fmt.Printf("Server: %s:%d\n", host, port)
    fmt.Printf("Debug: %v, Timeout: %v\n", debug, timeout)

    // 敏感数据
    secret := loader.GetSecure("API_KEY")
    if secret != nil {
        defer secret.Release()
        fmt.Printf("API Key length: %d\n", secret.Length())
    }

    // 应用到系统环境
    if err := loader.Apply(); err != nil {
        log.Fatal(err)
    }

    // 所有变量
    fmt.Printf("Loaded %d variables\n", loader.Len())
    fmt.Printf("Load time: %v\n", loader.LoadTime())
}

相关文档