Go 言語の定数の基礎

GolangBeginner
オンラインで実践に進む

はじめに

前のレッスンでは、Go 言語の変数について学びました。このレッスンでは、定数(Constants)の概念、その使用方法、そしてなぜ定数が重要なのかを詳しく見ていきましょう。定数の世界を探索しましょう。

学習ポイント:

  • 定数とは何か
  • 定数の宣言方法
  • 定数ジェネレータ iota
  • 定数の活用方法

定数とは何か?

簡単に言うと、定数とは宣言された後にプログラムの実行中に変更することができない値のことです。定数を使用すると、コンパイラはプログラムの実行前、つまりコンパイル段階でその値を知ることができます。

定数の宣言には特定の値を割り当てることができます。構文は変数と似ていますが、一度定数の値が宣言されると、それを書き換えることはできません。

定数は、Web サイトの URL や円周率(π)のような、変更すべきではない特定の意味を持つ値を定義する際に非常に便利です。

定数の宣言

定数の宣言は変数の宣言と似ていますが、キーワード var の代わりに const を使用します。

注意:定数は宣言時に必ず値を割り当てる必要があります。

Go 言語では、定義された変数は必ず使用しなければなりませんが、定数は例外です。定義した定数を使用しなくても、コンパイルエラーにはなりません。

定数を宣言する構文は以下の通りです:

const name [type] = value

name は宣言する定数の名前です。type は定数のデータ型ですが、Go が自動的に型推論を行うため省略可能です。最後の value は定数に割り当てる値です。

定数の宣言に使用できるのは、以下の型のみであることに注意してください:

  • 整数型(Integer types)
  • 浮動小数点型(Floating-point types)
  • 複素数型(Complex types)
  • 論理型(Boolean types)
  • 文字列型(String types)

例を見てみましょう。~/project ディレクトリに const.go という新しいファイルを作成します:

touch ~/project/const.go

const.go に以下のコードを入力します:

package main

import "fmt"

// 単一の定数を宣言
const labex string = "LabEx" // 明示的に string 型を指定
const labs = "LABS"    // コンパイラによって自動的に string 型と推論される

// 複数の定数を一括で宣言
const (
    hangzhou, chengdu = "HANGZHOU", "CHENGDU"
    monday, tuesday, wednesday = "MONDAY", "TUESDAY", "WEDNESDAY"
)

func main() {
    fmt.Printf("The type of labex is: %T, and its value is %s\n", labex, labex)
    fmt.Printf("The type of labs is: %T, and its value is %s\n", labs, labs)

    fmt.Println()

    fmt.Println(hangzhou, chengdu)
    fmt.Println(monday, tuesday, wednesday)
}
go run ~/project/const.go

プログラムを実行すると、以下のような出力が表示されます:

The type of labex is: string, and its value is LabEx
The type of labs is: string, and its value is LABS

HANGZHOU CHENGDU
MONDAY TUESDAY WEDNESDAY

ここでは、単一および複数の定数の宣言方法を示しました。複数の定数を宣言する場合は、括弧 () を使用するのが一般的です。

このプログラムでは文字列定数の宣言のみを示しましたが、定数は整数や論理値など他の型でも宣言できます。

括弧を使用して複数の定数を宣言する場合、定数が初期化されていないときは、直前の定数の値を継承します

const.go の内容を以下のように書き換えてみましょう:

package main

import "fmt"

const (
    monday    = "MONDAY"
    tuesday   = "TUESDAY"
    wednesday = "WEDNESDAY"
    thursday
    friday
)

func main() {
    fmt.Println(monday, tuesday, wednesday, thursday, friday)
}
go run ~/project/const.go

出力結果は以下の通りです:

MONDAY TUESDAY WEDNESDAY WEDNESDAY WEDNESDAY

ここで、thursdayfriday には明示的な値が設定されていません。Go のルールに従い、定数が明示的に初期化されていない場合、直前の定数の値を継承します。このケースでは:

  • thursdaywednesday の値を継承します。
  • fridaywednesday の値を継承します。

この動作によりコードを簡潔に記述できますが、意識していないと思わぬ結果を招くことがあります。

thursdayfriday にそれぞれ独自の値を設定したい場合は、明示的に代入する必要があります:

const (
    monday    = "MONDAY"
    tuesday   = "TUESDAY"
    wednesday = "WEDNESDAY"
    thursday  = "THURSDAY"
    friday    = "FRIDAY"
)

これにより、期待通りの出力が得られます:

MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY

定数ジェネレータ iota

定数を一つずつ宣言する以外に、iota を使って一括で宣言することもできます。例を見てみましょう。const.go ファイルに以下のコードを記述します:

package main

import "fmt"

const (
    monday    = iota // 初期値は 0
    tuesday   = iota // 項目ごとに 1 ずつ増加
    wednesday = iota
    thursday  = iota
    friday    = iota
)

func main() {
    fmt.Println(monday, tuesday, wednesday, thursday, friday)
}
go run ~/project/const.go

出力結果は以下の通りです:

0 1 2 3 4

iota を使用すると、初期値は 0 となり、それ以降の項目ごとに 1 ずつ加算されます。

最初の項目で iota を宣言すれば、それ以降の定数に iota を繰り返し記述する必要はありません。以下のコードも正しく動作します:

package main

import "fmt"

const (
    monday    = iota // 0
    tuesday          // 1
    wednesday        // 2
    thursday         // 3
    friday           // 4
)

func main() {
    fmt.Println(monday, tuesday, wednesday, thursday, friday)
}

特定の値をスキップしたい場合はどうすればよいでしょうか?その場合はアンダースコア(_)を使用します。以下のコードは、水曜日(Wednesday)に相当する値をスキップします:

package main

import "fmt"

const (
    monday  = iota // 0
    tuesday        // 1
    _
    thursday // 3
    friday   // 4
)

func main() {
    fmt.Println(monday, tuesday, thursday, friday)
}
go run ~/project/const.go

実行結果からわかるように、出力は以下のようになります:

0 1 3 4

iota 演算子は算術演算にも使用できます。const.go に以下のコードを入力してください:

package main

import "fmt"

const (
    a = iota     // 0
    b = iota * 3 // 1 * 3
    c = iota + 4 // 2 + 4
)

const (
    B  = 1 << (iota * 10) // 1 << (0 * 10) と等価
    KB                    // 1024
    MB                    // 1048576
)

func main() {
    fmt.Println(a, b, c)
    fmt.Println(B, KB, MB)
}
go run ~/project/const.go

出力結果は以下の通りです:

0 3 6
1 1024 1048576

最初の定数宣言グループでは、iota を使って簡単な算術演算を行っています。

2 番目のグループでは、iota と左シフト演算子 << を組み合わせて、1 KB1 MB の値をバイト(B)単位で表現しています。例えば、1 KB1024B1 MB1024 * 1024 つまり 1048576B となります。

チャレンジ

学んだことを復習しましょう。iota.go という新しいファイルを作成し、iota と定数を使用して 1GB と 1TB の値をバイト(B)単位で出力してください。

要件:

  1. 変換後の数値を直接出力しないでください。変換には iota を使用してください。
  2. iota.go ファイルは ~/project ディレクトリに配置してください。

ヒント: 「iota」セクションのコードを参考にしてください。

期待される出力形式は以下の通りです:

1GB is equal to 1073741824B
1TB is equal to 1099511627776B

まとめ

このレッスンで学んだ内容を振り返りましょう:

  • 定数は宣言後に変更することができません。
  • 定数は const キーワードを使用して宣言します。
  • 複数の定数を宣言する場合は、括弧 () を使用するのが推奨されます。
  • 定数ジェネレータ iota を使用すると、連続した値を列挙して宣言できます。
  • iota は算術演算の中でも利用可能です。

このレッスンでは定数について学び、あわせて iota 定数ジェネレータについても紹介しました。文字列、整数、浮動小数点数、そして定数は、Go 言語における基本的なデータ型です。

✨ 解答を確認して練習