🍟

【Go】複数の値が設定されている環境変数を扱う

2023/05/03に公開

環境変数に複数の値を設定したい場面は、少なくはないと思います。
一例として、Goのランタイムをコントロールする変数のGODEBUGは、,で区切って複数の値を設定します。

GODEBUG=http2client=0,http2server=0

このような複数の値を設定した環境変数を参照する Go のプログラムを考えてみましょう。

package main

import (
	"fmt"
	"os"
)

func main() {
	s := os.Getenv("KEY")
	fmt.Println(s)
}
$ KEY=hoge,fuga go run main.go
hoge,fuga

os.Getenvを用いて参照することができましたが、複数の値が設定されている環境変数は、文字列ではなくてスライスなどの構造的な値として扱いたいですよね。

本記事では、環境変数に複数の値を設定する場面における2つの解決策を紹介します。

,区切りで値を設定して、参照後に分割する

任意の文字列で文字列を分割するstrings.Splitを用いるパターンです。
,区切りで値を設定し、参照した値を,で分割します。
経験上こちらの方法を使用することが多いです。

package main

import (
	"fmt"
	"os"
	"strings"
)

func main() {
	s := os.Getenv("KEY")
	ss := strings.Split(s, ",")
	for _, v := range ss {
		fmt.Println(v)
	}
}
$ KEY=hoge,fuga go run main.go
hoge
fuga

JSONの配列で値を設定し、参照後にパースする

JSONをパースして、スライスに変換するパターンです。
JSONの配列の形式で値を設定し、参照した値をjson.Unmarshalでパースします。
正直Goでの参照、変換の観点での利点は思いつかないです。
ですが、開発/運用における制約として環境変数の値をJSON形式で縛るのは悪くは無いと思うので、そういった状況下においては有用であると考えます。

package main

import (
	"encoding/json"
	"fmt"
	"os"
)

func main() {
	s := os.Getenv("KEY")
	var ss []string
	if err := json.Unmarshal([]byte(s), &ss); err != nil {
		fmt.Println(err)
		return
	}
	for _, v := range ss {
		fmt.Println(v)
	}
}
KEY=[\"hoge\",\"fuga\"] go run main.go
hoge
fuga

最後に

今回は私の経験をもとに2つのアプローチを紹介しました。
他にも効果的なアプローチがあれば、是非コメント等いただけると幸いです。

参考

Discussion