変数・スコープ¶
はじめに¶
本サイトにつきまして、【IT技術の知見】はじめに - 俺の技術ノート をご認識のほど宜しくお願いいたします。
01. 変数¶
定義 (宣言+代入)¶
▼ 明示的な定義¶
// 1個の変数を定義 (宣言と代入が同時でない)
var number int
number = 5
// 1個の変数を定義 (宣言と代入が同時)
var number int = 5
// 複数の変数を定義
var foo, bar, baz int
foo, bar, baz = 1, 3, 5
▼ 暗黙的な定義 (型推論)¶
// データ型が自動的に認識される
w := 1
x := true
y := 3.14
z := "abc"
var w = 1
var (
foo = true
y = 3.14
z = "abc"
)
package main
import "fmt"
func quotient(x int, y int) int {
// 商を計算する。
quotient := x / y
// を返却する。
return quotient
}
func main() {
fmt.Println(quotient(2, 2))
}
▼ 再宣言¶
基本的には、同じスコープ内で既存の変数を再宣言できない。
ただし、複数の変数を宣言するときは注意する。いずれかに新しい変数の宣言が含まれていれば、既存の変数を宣言したとしても代入のみが実行される。
package main
import (
"log"
)
func main() {
foo := 1
// 新しい変数の宣言が含まれている
foo, bar := 2, 3
log.Printf("%v", foo) // 2
log.Printf("%v", bar) // 3
}
定義位置の種類¶
▼ グローバル変数¶
関数の外部で定義した変数のこと。
スコープとして、宣言されたパッケージ外部でも使用できる。
グローバル変数を宣言し、関数内で値を代入する。
package main
import (
"log"
)
// グローバル変数
var text string
func main() {
text = "Hello World!"
log.Printf("%v", text)
}
変数に対する代入は関数内でしかできないため、宣言と代入を同時に実行する型推論を使用するとエラーになってしまう。
package main
import (
"log"
)
// エラーになってしまう。
text := "Hello World!"
func main() {
log.Printf("%v", text)
}
▼ ローカル変数¶
関数の内部で定義した変数のこと。
スコープとして、宣言されたパッケージ内部でしか使用できない。
package main
import (
"log"
)
func main() {
// ローカル変数
text := "Hello World!"
log.Printf("%v", text)
}
02. 環境変数¶
環境変数の出入力¶
▼ init() 関数による環境変数出力¶
環境変数は、.env ファイルを使用する以外に、init() 関数で出力する方法もある。
▼ アプリ側の環境変数¶
package config
import "os"
// 環境変数名を設定する
const (
FooEnvKey = "FOO"
BarEnvKey = "BAR"
BazEnvKey = "BAZ"
)
func init() {
// 環境変数名を指定して値を格納する
os.Setenv(FooEnvKey, "foo")
os.Setenv(BarEnvKey, "bar")
os.Setenv(BazEnvKey, "baz")
}
▼ パッケージ側の環境変数¶
パッケージ側では、アプリケーションが設定した環境変数を出力できるような処理が必要になる。
このとき、フォールバック (変数や定数に値が格納されていない場合に、代わりに使用する処理) で環境変数を取得すると、デフォルト値を設定できる。
環境変数が string 型か float64 型かに合わせて、関数を定義しておく。
package config
import (
"os"
"strconv"
)
// 環境変数名を設定する
const (
FooEnvKey = "FOO"
BarEnvKey = "BAR"
BazEnvKey = "Baz"
QuxEnvKey = "QUX"
)
var (
foo string
bar string
baz float64
qux bool
)
func init() {
getEnvs()
}
func getEnvs() {
// 環境変数名を指定して値を取得する
foo = getStringEnv(FooEnvKey, "foo")
bar = getStringEnv(BarEnvKey, "bar")
baz = getFloatEnv(BazEnvKey, 1.0)
qux = getBoolEnv(QuxEnvKey, false)
}
// 環境変数をstring型で取得する
func getStringEnv(key string, fallback string) string {
value := os.Getenv(key)
// マイクロサービス側で値を設定していれば、それを使用する
if len(value) != 0 {
return value
}
// 環境変数の値が空文字だった場合は、fallbackをデフォルト値として返却する
return fallback
}
// 環境変数をfloat64型で取得する
func getFloatEnv(key string, fallback float64) float64 {
value, err := strconv.ParseFloat(getStringEnv(key, strconv.FormatFloat(fallback, 'f', -1, 64)), 64)
if err != nil {
return fallback
}
return value
}
// 環境変数をbool型で取得する
func getBoolEnv(key string, fallback bool) bool {
value, err := strconv.ParseBool(getStringEnv(key, strconv.FormatBool(fallback)))
if err != nil {
return fallback
}
return value
}
string 型以外の値¶
環境変数はすべて string 型で定義する必要がある。
そのため、出入力前に string 型への (からの) 変換が必要になる。
// int型をstring型に変換した上で、環境変数として設定する
os.Setenv("FOO_TIMEOUT", strconv.Itoa(300))
// bool型をstring型に変換した上で、環境変数として設定する
os.Setenv("FOO_ENABLED", strconv.FormatBool(true))
03. スコープ¶
変数、定数¶
▼ パッケージ内外から参照可能¶
変数名または定数名の頭文字を大文字すると、パッケージ内外でこれをコールできるようになる。
package foo
// 定数を定義する。
const (
Foo = "foo"
)
package main
import (
"log"
)
func main() {
log.Printf("%v", Foo) // foo
}
▼ パッケージ内のみ参照可能¶
変数名または定数名の頭文字を小文字すると、パッケージ外でこれをコールできなくなる。
package foo
// 定数を定義する。
const (
Bar = "bar"
)
package main
import (
"log"
)
func main() {
log.Printf("%v", Bar) // コールできずにエラーになる
}
関数¶
▼ パッケージ内外から参照可能¶
関数名の頭文字を大文字すると、パッケージ内外でこれをコールできるようになる。
package foo
func Foo() {
// 何らかの処理
}
package main
func main() {
Foo()
}
▼ パッケージ内のみ参照可能¶
関数名の頭文字を小文字すると、パッケージ外でこれをコールできなくなる。
package main
func foo() {
// 何らかの処理
}
func main() {
foo()
}