golang环境变量加载到结构体的轻量级插件库env的使用
Golang环境变量加载到结构体的轻量级插件库env的使用
关于
这个包是为那些将配置存储在环境变量中的应用设计的。它的目的是用单一的结构体定义替换main.go
中分散的os.Getenv
调用,从而简化配置管理并提高代码可读性。
功能特性
安装
Go 1.20+
go get go-simpler.org/env
使用
Load
是包的主要函数,它将环境变量加载到给定的结构体中。
结构体字段必须有env:"VAR"
标签,其中VAR
是对应的环境变量名。未导出的字段会被忽略。
os.Setenv("PORT", "8080")
var cfg struct {
Port int `env:"PORT"`
}
if err := env.Load(&cfg, nil); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.Port) // 8080
支持的类型
int
(任意种类)float
(任意种类)bool
string
time.Duration
encoding.TextUnmarshaler
- 上述任意类型的切片
- 任意深度的嵌套结构体
解析规则参考strconv.Parse*
函数。用户定义类型可以通过实现encoding.TextUnmarshaler
接口来使用。
嵌套结构体
支持任意深度的嵌套结构体,允许对相关的环境变量进行分组。
os.Setenv("DB_HOST", "localhost")
os.Setenv("DB_PORT", "5432")
var cfg struct {
DB struct {
Host string `env:"DB_HOST"`
Port int `env:"DB_PORT"`
}
}
if err := env.Load(&cfg, nil); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.DB.Host) // localhost
fmt.Println(cfg.DB.Port) // 5432
如果嵌套结构体有可选的env:"PREFIX"
标签,则其字段声明的环境变量会加上PREFIX
前缀。
os.Setenv("DB_HOST", "localhost")
os.Setenv("DB_PORT", "5432")
var cfg struct {
DB struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
} `env:"DB_"`
}
if err := env.Load(&cfg, nil); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.DB.Host) // localhost
fmt.Println(cfg.DB.Port) // 5432
默认值
可以使用default:"VALUE"
结构体标签指定默认值。
os.Unsetenv("PORT")
var cfg struct {
Port int `env:"PORT" default:"8080"`
}
if err := env.Load(&cfg, nil); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.Port) // 8080
必填项
使用required
选项将环境变量标记为必填。如果未设置,则返回类型为NotSetError
的错误。
os.Unsetenv("PORT")
var cfg struct {
Port int `env:"PORT,required"`
}
if err := env.Load(&cfg, nil); err != nil {
var notSetErr *env.NotSetError
if errors.As(err, ¬SetErr) {
fmt.Println(notSetErr) // env: PORT is required but not set
}
}
扩展
使用expand
选项使用os.Expand
自动扩展环境变量的值。
os.Setenv("PORT", "8080")
os.Setenv("ADDR", "localhost:${PORT}")
var cfg struct {
Addr string `env:"ADDR,expand"`
}
if err := env.Load(&cfg, nil); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.Addr) // localhost:8080
切片分隔符
空格是解析切片值的默认分隔符。可以使用Options.SliceSep
更改。
os.Setenv("PORTS", "8080,8081,8082")
var cfg struct {
Ports []int `env:"PORTS"`
}
if err := env.Load(&cfg, &env.Options{SliceSep: ","}); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.Ports) // [8080 8081 8082]
名称分隔符
默认情况下,环境变量名称是从嵌套结构体标签原样拼接的。如果Options.NameSep
不为空,则用作分隔符。
os.Setenv("DB_HOST", "localhost")
os.Setenv("DB_PORT", "5432")
var cfg struct {
DB struct {
Host string `env:"HOST"`
Port int `env:"PORT"`
} `env:"DB"`
}
if err := env.Load(&cfg, &env.Options{NameSep: "_"}); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.DB.Host) // localhost
fmt.Println(cfg.DB.Port) // 5432
来源
默认情况下,Load
直接从操作系统获取环境变量。要使用不同的来源,通过Options.Source
传递Source
接口的实现。
type Source interface {
LookupEnv(key string) (value string, ok bool)
}
这是一个使用Map
的示例,Map
是一个在测试中很有用的Source
实现。
m := env.Map{"PORT": "8080"}
var cfg struct {
Port int `env:"PORT"`
}
if err := env.Load(&cfg, &env.Options{Source: m}); err != nil {
fmt.Println(err)
}
fmt.Println(cfg.Port) // 8080
使用信息
Usage
函数打印一个使用信息,记录所有定义的环境变量。可以使用usage:"STRING"
结构体标签为环境变量添加可选的用法字符串。
os.Unsetenv("DB_HOST")
os.Unsetenv("DB_PORT")
var cfg struct {
DB struct {
Host string `env:"DB_HOST,required" usage:"database host"`
Port int `env:"DB_PORT,required" usage:"database port"`
}
HTTPPort int `env:"HTTP_PORT" default:"8080" usage:"http server port"`
}
if err := env.Load(&cfg, nil); err != nil {
fmt.Println(err)
fmt.Println("Usage:")
env.Usage(&cfg, os.Stdout, nil)
}
输出:
Usage:
DB_HOST string required database host
DB_PORT int required database port
HTTP_PORT int default 8080 http server port
可以通过实现Usage([]env.Var, io.Writer, *env.Options)
方法来自定义消息的格式。
type Config struct{ ... }
func (Config) Usage(vars []env.Var, w io.Writer, opts *env.Options) {
for v := range vars {
// write to w.
}
}
更多关于golang环境变量加载到结构体的轻量级插件库env的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang环境变量加载到结构体的轻量级插件库env的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang环境变量加载到结构体的轻量级插件库 - env
env是一个轻量级的Go库,用于将环境变量加载到结构体中。它简单易用,支持各种数据类型和自定义解析器。下面我将介绍env的基本用法和示例代码。
安装
go get github.com/caarlos0/env/v8
基本用法
简单示例
package main
import (
"fmt"
"time"
"github.com/caarlos0/env/v8"
)
type config struct {
Home string `env:"HOME"`
Port int `env:"PORT" envDefault:"3000"`
Password string `env:"PASSWORD,unset"`
IsProduction bool `env:"PRODUCTION"`
Duration time.Duration `env:"DURATION"`
Hosts []string `env:"HOSTS" envSeparator:":"`
}
func main() {
cfg := config{}
if err := env.Parse(&cfg); err != nil {
fmt.Printf("%+v\n", err)
}
fmt.Printf("%+v\n", cfg)
}
标签说明
env:"VARNAME"
- 指定环境变量名envDefault:"value"
- 设置默认值unset
- 加载后从环境中删除该变量envSeparator:"|"
- 指定切片类型的分隔符(默认为逗号)required
- 标记字段为必填
高级用法
嵌套结构体
type config struct {
Database struct {
User string `env:"DB_USER" envDefault:"postgres"`
Password string `env:"DB_PASSWORD"`
Host string `env:"DB_HOST" envDefault:"localhost"`
Port int `env:"DB_PORT" envDefault:"5432"`
}
Server struct {
Port int `env:"SERVER_PORT" envDefault:"8080"`
}
}
func main() {
cfg := config{}
if err := env.Parse(&cfg); err != nil {
panic(err)
}
fmt.Printf("%+v\n", cfg)
}
自定义解析器
type customType string
func (c *customType) UnmarshalText(text []byte) error {
*c = customType(fmt.Sprintf("custom-%s", string(text)))
return nil
}
type config struct {
Custom customType `env:"CUSTOM"`
}
func main() {
os.Setenv("CUSTOM", "value")
cfg := config{}
if err := env.Parse(&cfg); err != nil {
panic(err)
}
fmt.Println(cfg.Custom) // 输出: custom-value
}
必填字段
type config struct {
SecretKey string `env:"SECRET_KEY,required"`
}
func main() {
cfg := config{}
if err := env.Parse(&cfg); err != nil {
fmt.Println(err) // 会返回错误,因为SECRET_KEY未设置
}
}
从文件加载
type config struct {
SecretKey string `env:"SECRET_KEY,file"`
}
func main() {
// 假设有一个文件路径存储在SECRET_KEY_FILE环境变量中
os.Setenv("SECRET_KEY_FILE", "/path/to/secret_key.txt")
cfg := config{}
if err := env.Parse(&cfg); err != nil {
panic(err)
}
fmt.Println(cfg.SecretKey) // 输出文件内容
}
最佳实践
- 在main函数或init函数中尽早加载配置
- 为所有配置项提供合理的默认值
- 对生产环境必需的配置使用
required
标签 - 敏感信息考虑使用
file
标签从文件加载 - 使用嵌套结构体组织相关配置项
与其他库的比较
env库相比其他配置库(如viper)有以下特点:
- 更轻量级,只专注于环境变量到结构体的映射
- 更简单的API,只有一个主要函数
Parse
- 支持自定义解析器
- 支持从文件加载敏感信息
env库适合简单的配置需求,特别是12-factor应用。如果需要更复杂的配置来源(如JSON/YAML文件、命令行参数等),可以考虑使用viper等更全面的配置库。
希望这个介绍对你有帮助!env库简单易用,是处理环境变量配置的不错选择。