env 環境變數

jacobxy發表於2021-11-26

env 環境變數獲取庫

背景

對於編譯成二進位制檔案的程式而言,其本身就是一個黑盒子。程式的外部控制主要由三個部分組成:命令列引數,配置檔案和環境變數。之前的文章中,我們已經擁有命令列引數工具庫 cobra,配置檔案讀取庫 viper,今天我們來了解一下在環境變數讀取庫中的一員 env。

安裝

go get github.com/caarlos0/env/v6

使用案例

package main

import (
    "fmt"
    "time"

    "github.com/caarlos0/env/v6"
)

type config struct {
    Home         string        `env:"HOME"`
    Port         int           `env:"PORT" envDefault:"3000"`
    Password     string        `env:"PASSWORD,unset"`
    IsProduction bool          `env:"PRODUCTION"`
    Hosts        []string      `env:"HOSTS" envSeparator:":"`
    Duration     time.Duration `env:"DURATION"`
    TempFolder   string        `env:"TEMP_FOLDER" envDefault:"${HOME}/tmp" envExpand:"true"`
}

func main() {
    cfg := config{}
    if err := env.Parse(&cfg); err != nil {
        fmt.Printf("%+v\n", err)
    }

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

接下來我們針對程式碼中涉及的 tag 逐一進行分析:

  • env:環境變數的獲取名。
    • unset:與 env 逗號隔開,表明環境變數值獲取之後即刻清理,通常用於私密資料。
    • file:將對應檔案內容讀取賦值。
    • required: 畢竟從環境變數中讀取到。
    • notEmpty: 非空
  • envDefault: 顧名思義,當獲取不到環境變數值時的預設值。
  • envSeparator: 當變數是字串陣列時,此值對應切分時使用的字元。
  • envExpand:通常與 envDefault 配合使用,允許使用環境變數對 envDefault 的值格式化。

擴充套件

env 庫的公開函式中,使用 ParseWithFuncs 可以傳入自定義的型別解析函式,其型別為 map[reflect.Type] func(v string) (interface{}, error)。如此通過形如 type Myint int 的方式,讓解析過程能擁有更大的靈活性。

原始碼悄悄看

env 庫的主要功能原始碼不過 500 行,其中使用了大量 reflect 庫的反射機制,用於對環境變數值到結構體成員型別的轉換,defaultBuiltInParsers 定義了其預設的型別解析函式。 解析流程:

  • 通過 os.Environ() 獲得環境變數字串 key=value 形式,轉換成 map[string] string 結構。
  • 通過反射迴圈獲取結構體變數資訊,包括變數型別和對應 tag
  • 使用設定對應的解析函式,其中若是結構體則遞迴呼叫
  • 根據 tag 指定的邏輯對解析後的值進行判斷和處理
  • 對結構體變數賦值

總結

環境變數在程式中的使用隨著微服務專案的普及而越來越常見。環境變數可以看作是作業系統層面的配置檔案,因此我們通常會把與業務相關的引數寫在配置檔案中,會把與程式系統功能相關的引數配置在環境變數中。

相關連結

https://github.com/caarlos0/env

更多原創文章乾貨分享,請關注公眾號
  • env 環境變數
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章