Go言語 定数

定数とは、プログラムの実行中に変更することができない固定された値のことです。Goでは、定数はconstキーワードで宣言され、文字列、整数、浮動小数点、ブーリアンなどの組み込み型等を使用することができます。

Go言語 定数の宣言

以下は、Goで定数を宣言する方法の例です。

const pi float64 = 3.14159265358979323846

この例では、piという名前の定数を宣言しています。定数の型は、型付け構文を使って明示的にfloat64として宣言されていることに注意してください。型が明示的に宣言されていない場合、Goは定数に割り当てられた値に基づいて型を推論します。

重要なのは、定数が一度宣言されると、その値は変更できないことです。定数に値を再割り当てしようとすると、コンパイルエラーになります。

また、Goでは定数は宣言時に必ず初期値が割り当てられていなければなりません。もし初期値を与えなければ、コンパイラはエラーになります。

const pi float64

Go言語 型宣言なしの定数

定数も変数と同様に型宣言をせずに値を代入できますが、変数とは少し違う部分があります。 Goでは、型宣言をせずに定数に値を代入した場合、型なしという状態になります。

例として、int型の最大値を変数と定数で扱った場合どうなるかを見てみましょう。int型の最大値は、64bitの場合9223372036854775807です。int型の最大値を超える値を変数に代入すると、オーバーフローとなりエラーとなります。

// error
var number = 9223372036854775807 + 1

しかし、定数に同じ値を代入しても、定数は型付けされていない整数型の状態であるため、オーバーフローには至りません。

const number = 9223372036854775807 + 1

この場合の定数numberは型なしの整数型という状態になっており、明示的な整数型として扱われません。

型付けされていない定数の型は、それが型定義された方法で使われたときに初めて決定されます。定数の段階では型なしの整数型でしたが、それを型が指定されている変数や、 型が推論できるような変数に代入した段階でその型と結びつき、その型として表現されることになります。

// この時点では問題なし
const number = 9223372036854775807 + 1

// エラー
x := number

例えば、定数 math.Piはよく使われる定数で、πの値を表します。

定数の段階では、math.Piは型付けされていない浮動小数点数定数です。これは、明示的に定義された型を持っておらず、まだ明示的な浮動小数点型として表現されていないことを意味します。math.Piの型は、それが型定義された方法で使用されるときにのみ決定されます。

例えば、math.Piが32ビット浮動小数点型変数として扱われた場合、3.1415927に丸められます。一方、64ビット浮動小数点型変数として扱われる場合は、3.141592653589793に丸められます。

var i float32 = math.Pi // 3.1415927
var j float64 = math.Pi // 3.141592653589793

Go言語 定数とミュータブル

Goでは、定数は定義上、コンパイル時の値であり、一度値が割り当てられると変更できないイミュータブル(不変)であることに注目すべきです。これは、実行時に変更可能な変数とは異なります。

このため、定数は円周率や1日の秒数といった数学の定数のように、変化しない値を指定する場合にのみ使用することができます。配列、マップ、構造体は、実行時に変更可能なミュータブルであるため、定数として割り当てることはできません。

したがって、以下のような使い方はできません。

const arr []string = []string{"golang", "python", "java"}

例えばJavaScriptもconstによって定数を扱うことができますが、再代入さえしなければ、オブジェクトなども代入することができます。それに対し、Goの定数はかなり制限された使い方になっています。そのかわり安全に定数を利用することができます。

Go言語 複数の定数の宣言

Goでは、定数はいくつかの方法で宣言し、初期化することができます。そのうちの1つが、シーケンスとして宣言する方法です。

3つの定数a,b,cをシーケンスで定義し、それぞれ1,2,3という初期値を与えてみましょう。これは、同時に定義したい値が複数ある場合に便利な定数の書き方です。

const (
    a int = 1
    b int = 2
    c int = 3
)

もう1つの方法は自動的に代入する方法です。

const (
    d int = 1
    e
    f
)

3つの定数d,e,fを順番に定数として宣言します。dには初期値として1が与えられており、eとfは初期値が明示されていないため、順番の前の定数の値が自動的に代入されるようになっています。この場合、eとfはともに1という値が与えられます。

このように定数を宣言する方法は、同じ値を持つ定数を複数定義したい場合に有効です。

Go言語 iota

Goでは、iotaは値の並びを表現するために使われる特別な定数です。各定数が一意な値を持つ列挙型を表現するためによく使われます。iotaは行が変わるたびに自動的にインクリメントされる特別な定数です。

ここでは、iotaを使って曜日を表す定数のセットを定義する例を示します。

const (
    Monday = iota // 0
    Tuesday = iota // 1
    Wednesday = iota // 2
    Thursday = iota // 3
    Friday = iota // 4
    Saturday = iota // 5
    Sunday = iota // 6
)

また、連続して記述する場合、2行目以降は省略できるため、以下のようにも書けます。

const (
    Monday = iota
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
    Sunday
)

iotaは、2の累乗を定義するビット演算でよく使われます。

const (
    One = 1 << iota // 1
    Two // 2
    Four // 4
    Eight // 8
)

この例では、各定数は2の累乗で定義されており、最初の定数Oneは1を0だけ左にシフトしたもので、1に相当します。次の定数Twoは1を1だけ左にシフトしたもので、2に相当します。次の定数FourとEightも同様に、それぞれ1を2,3だけ左にシフトし4,8と定義されています。

Note: <<はビットシフト表します。例えば定数のFourは1を2回左へビットシフトするので、2進数で考えると1 → 100を計算することになります。したがって、4が出力になります。

これを応用すれば、例えばギガバイト(GB)やテラバイト(TB)をキロバイト(KB)として簡潔に記述することもできます。

const (
    _ = iota
    KB = 1 << (10 * iota) // 1 << 0 = 1
    MB = 1 << (10 * iota) // 1 << 10 = 1024
    GB = 1 << (10 * iota) // 1 << 20 = 1048576
    TB = 1 << (10 * iota) // 1 << 30 = 1073741824
)

この記事を書いた人

著者の画像

Jeffry Alvarado

Ex-Facebook Engineer 大学ではコンピュータサイエンスを専攻し、在学中に複数のインターンシップを経験。コンピュータサイエンスが学習できるプラットフォームRecursionを創業し、CTOとしてカリキュラム作成、ソフトウェア開発を担当。


ツイート