> Source: https://www.ymotongpoo.com/works/goblog-ja/constants/


# 定数
[Constants](https://blog.golang.org/constants) by Rob Pike

## はじめに
Goは、数値型を混合して操作することを許さない静的型付け言語です。 `float64` を `int` に
足せませんし、さらに言えば `int32` を `int` に足すこともできません。しかし、 `1e6*time.Second` や
`math.Exp(1)` あるいは `1<<('\t'+2.0)` と書くことは許されています。Goでは、定数は変数と違って、
通常の数字と同様に振る舞います。この記事では、なぜそうなっているのか、そしてそれが何を意味するのかを
説明します。

## 背景: C言語

Go言語を考え始めた初期の頃、C言語やその系譜の言語が数値型をまぜこぜに使うことを許していることで起きている多くの問題について話しました。
多くの奇妙なバグ、クラッシュ、移植可能性の問題は、サイズと「符号有無」が異なる整数を混ぜている式によって起きています。
経験の多いCプログラマにとっても、次の計算結果はわかるかもしれませんが、アプリオリには明らかではありません。

```go
unsigned int u = 1e9;
long signed int i = -1;
... i + u ...
```

結果はどれくらいの大きさになるのでしょう。その値はなんでしょうか。符号は付いているのかいないのか。

厄介なバグがここに潜んでいます。

C言語には「the usual arithmetic conversions」と呼ばれる規則があります。年月を経てその規則が変わってきたこと自体が、この規則の微妙さの表れであり、長年にわたって多くのバグを生んできました。

Goを設計するときに、数値型を混ぜてはいけないということをしっかりと決めることでこの地雷原を避けることにしました。
`i` と `u` を足したい場合には、結果をどうしたいかを明示しなければいけません。次のように変数があったとして、

```go
var u uint
var i int
```

`uint(i)+u` または `i+int(u)` のどちらかで書けます。これはどちらの書き方でも足し算の意味と型がはっきりと表現されていますが、
C言語の場合とは異なって `i+u` と書くことはできません。 `int` が32ビット型の場合でさえ、 `int` と `int32` を混ぜることすらできません。

この厳格さによって、よくありがちなバグや他の問題が取り除かれます。これはGoにおいて非常に重要な性質です。
しかしこの厳格さにはコストが掛かります。意味を自明にするために、ときにこの厳格さがプログラマに不格好な
型変換のコードを追加することを求めます。

では定数ではどうでしょうか。これまでに述べてきたことからすると、どうすれば規則を守ったまま `i = 0` または `u = 0` と書けるでしょうか。
`0` の型は何でしょうか。単純な状況、たとえば `i = int(0)` のような場面で、型変換を書かなければいけないのは筋がよくありません。

私たちはすぐに数値の定数を扱う場合には、C言語に似た他の言語での動作とは異なる振る舞いをさせれば良いと気が付きました。
多くの考察と実験の後に、ほぼ常に正しいと信じられ、つねにプログラマを定数の型変換から解放し、それでいてコンパイラに
警告されることなく `math.Sqrt(2)` のように書ける設計を思いつきました。

手短に言えば、Goの定数は、とにかくほとんどの場合、うまく動きます。ではそれがどのようになっているか見てみましょう。

## 用語解説

まず、手短に定義します。Goでは `const` は `2` 、 `3.14159` 、 `"scrumptious"` といったスカラー値に対する名前を決める
キーワードです。このような値は、名前が付いているかにかぎらず、Goでは _定数_ と呼ばれます。定数は定数からなる式からも
生成することが出来ます。たとえば `2+3` 、 `2+3i` 、 `math.Pi/2` あるいは `("go"+"pher")` といったものがそれです。

定数がない言語もありますし、 `const` という単語に対してより汎用的な定義がある言語やより汎用的な用途がある言語もあります。
たとえばC言語やC++では、 `const` はより複雑な値のより複雑な性質を分類する型修飾子です。

しかしGoでは、定数はとても単純で、変化しない値のことを指します。以降はGoでの場合のみを話します。

## 文字列定数

数値の定数には多くの種類があります。たとえば整数、浮動小数点数、ルーン（訳注：Unicodeのコードポイントを表す整数値）、符号あり、符号なし、虚数、複素数などがあります。
まずはより単純な形式の定数である文字列定数から話を始めましょう。文字列定数は理解がしやすく、Goにおける定数の型の問題を調べるときにより小さな部分だけ考えればよくなります。

文字列定数はある文字列をダブルクォーテーションで囲ったものです。（Goにはraw文字列リテラルもあり、バッククォートで囲みます。
ただしこの議論では両者を同じものとして扱います。）ここに文字列定数があります。

```go
"Hello, 世界"
```

（文字列の表現と解釈に関してより詳しい内容は[こちらのブログポスト](https://blog.golang.org/strings)を参照してください。）

この文字列定数はどんな型でしょうか。見たままで答えれば `string` ですが、それは _間違い_ です。

これは _型付けされていない文字列定数_ で、不変の文字列の値を持っているがまだ決まった型がないもの、といえるでしょう。
そうです、これは文字列なのですが、Goでの `string` 型の値ではないのです。型付けされていない文字列定数は、名前を与えた時にも
同様のままでいます。

```go
const hello = "Hello, 世界"
```

この宣言のあと、 `hello` もまた型付けされていない文字列定数となります。型付けされていない定数はただの値であり、
異なる型どうしの結合を禁じる厳格な規則に従うことを強いる、決まった型をまだ与えられていない値です。

この _型付けされていない_ 定数という考え方によって、Goで定数を自由度高く使うことができるのです。

それでは _型付けされた_ 文字列定数とはなんなのでしょう。それは次のように型を与えられた定数のことです。

```go
const typedHello string = "Hello, 世界"
```

`typedHello` の宣言は、等号の前で `string` 型が明示されていることに注目してください。これは `typedHello` が
Goの `string` 型であることを意味していて、Goでの異なる型の変数に代入できないことを意味しています。
これは次のコードは動きますが、

```go
var s string
s = typedHello
fmt.Println(s)
```

このコードは動かないということです。

```go
type MyString string
var m MyString
m = typedHello // 型エラー
fmt.Println(m)
```

変数 `m` は `MyString` 型で、異なる型には値は代入できません。 `MyString` 型の値のみ代入できます。
たとえば次のコードを見てください。

```go
const myStringHello MyString = "Hello, 世界"
m = myStringHello // OK
fmt.Println(m)
```

あるいは型変換をさせてもできるでしょう。

```go
m = MyString(typedHello)
fmt.Println(m)
```

_型付けされていない_ 文字列定数の話に戻ると、型がないことによって、型付けされた変数に代入しても
型エラーが発生させないというのは役に立つ性質です。つまり、このようなコードや

```go
m = "Hello, 世界"
```

あるいはこのように書けるのです。

```go
m = hello
```

なぜなら、型付けされた定数の `typedHello` や `myStringHello` とは違って、型付けされていない定数の `"Hello, 世界"` や
`hello` には _型がないからです_ 。 `string` と互換性のあるどのような型の変数にもエラーなしで代入できます。

これらの型付けされていない文字列定数はもちろん文字列であるため、文字列を使ってよい場所であればどこでも使えますが、
`string` という _型_ を持っていないのです。

## デフォルト型

Goのプログラマであるあなたは、まちがいなく次のような宣言を数多く見てきたことでしょう。

```go
str := "Hello, 世界"
```

ここまでの説明を読んで、「もし定数が型付けされていないのであれば、どうやって `str` はこの変数宣言で型を得るのだろう」と疑問に思ったことでしょう。
その答えはというと、型付けされていない定数にはデフォルトの型、つまり型が与えられてなかった場合に必要なときに値に対して与える暗黙的な型を持っているということです。
型付けされていない文字列定数であれば、デフォルト型は明らかに `string` なので、

```go
str := "Hello, 世界"
```

や

```go
var str = "Hello, 世界"
```

は次の宣言とまったく同じ意味になります。

```go
var str string = "Hello, 世界"
```

型付けされていない定数について考える1つの方法としては、それらは値の理想的な空間にいて、そこではGoの完全な型システムほど
制限がないと思えばいいでしょう。しかしその定数にたいして何かしたいと思ったら、それを変数に代入する必要があり、
変数に代入するときには（定数自身ではなく） _変数_ には型が必要で、その定数は変数に対して自分がどのような型であるべきか
伝えることができます。この例では `str` は `string` 型の値になります。なぜなら型付けされていない文字列定数は
そのデフォルト型である `string` であると宣言するからです。

このように変数宣言をした場合、その変数は型と初期値を含めて宣言されています。しかしながら、定数を使う際に、その値の
代入先がはっきりしない場合もあります。たとえば次の文を考えてみましょう。

```go
fmt.Printf("%s", "Hello, 世界")
```

`fmt.Printf` のシグネチャは次のとおりです。

```go
func Printf(format string, a ...interface{}) (n int, err error)
```

これは、この関数の（フォーマット文字列のあとの）引数がインターフェース値であることを意味しています。 `fmt.Printf` が
型付けされていない定数を使って呼び出された場合、インターフェース値が作られて引数に渡されます。そしてその引数に保存される
具象型はその定数のデフォルト型になります。このプロセスは先に型付けされていない文字列定数で初期値を宣言した状況に似ています。

この結果は次の例で確認できます。ここでは `fmt.Printf` で値を表示するのにフォーマット文字 `%v` を使い、値の型を表示するのに `%T` を使っています。

```go
fmt.Printf("%T: %v\n", "Hello, 世界", "Hello, 世界")
fmt.Printf("%T: %v\n", hello, hello)
```

（訳注: 出力は次のとおりです。）

```go
string: Hello, 世界
string: Hello, 世界
```

もし定数に型があれば、それがインターフェースに伝わり、次の例のようになります。

```go
fmt.Printf("%T: %v\n", myStringHello, myStringHello)
```

（訳注: 出力は次のとおりです。）

```go
main.MyString: Hello, 世界
```

（インターフェース値がどのように扱われるかをより詳しく知りたい場合は、次の
[ブログポスト](https://blog.golang.org/laws-of-reflection) の最初の節を参照してください。）

まとめとして、型付けされた定数はGoの型付けされた値のルールに従います。一方で、型付けされていない定数は
同じやり方でGoの型を決めるのではなく、より自由に型を混ぜたり一致させたりします。しかしながら、
明示的なデフォルト型が、他の型情報が得られない場合、そしてその場合に限り姿を現します。

## 構文から決定されるデフォルト型
型付けされていない定数のデフォルト型は構文により決定されます。文字列定数であれば、唯一取りうる
暗黙型は `string` です。 [数値定数](http://golang.org/ref/spec#Numeric_types) の場合は
暗黙型はより多くの種類を取り得ます。整数定数は `int` がデフォルト型ですし、浮動小数点数定数は
`float64` 、 ルーン定数は `rune` （ `int32` のエイリアス）、虚数定数は `complex128` がデフォルト型です。
ここで、お馴染みのprint文でデフォルト型を実際に動かして確認しましょう。

```go
fmt.Printf("%T %v\n", 0, 0)
fmt.Printf("%T %v\n", 0.0, 0.0)
fmt.Printf("%T %v\n", 'x', 'x')
fmt.Printf("%T %v\n", 0i, 0i)
```

（演習： `'x'` の場合の結果を説明しなさい。）

## 真偽値
型付けされていない文字列定数について話したことはすべて型付けされていない真偽値定数についてもあてはまります。
`true` と `false` はどのような真偽値の変数にも代入できる型付けされていない真偽値定数で、一度型が与えられると
混ぜることは出来ません。

```go
type MyBool bool
const True = true
const TypedTrue bool = true
var mb MyBool
mb = true      // OK
mb = True      // OK
mb = TypedTrue // ダメ
fmt.Println(mb)
```

上の例を実行して何が起きるか見たあと、 "ダメ" とコメントされている行をコメントアウトして
再び実行してみましょう。ここにあるパターンはすべて文字列定数の場合の規則に従っています。

## 浮動小数点数
浮動小数点数定数は多くの場合真偽値定数と同様です。これまで何度か出している例は浮動小数点数の場合にも
適用できます。

```go
type MyFloat64 float64
const Zero = 0.0
const TypedZero float64 = 0.0
var mf MyFloat64
mf = 0.0       // OK
mf = Zero      // OK
mf = TypedZero // ダメ
fmt.Println(mf)
```

ひとつ注意しておきたい点として、Goには _2つの_ 浮動小数点数型があることです。
`float32` と `float64` です。型付けされていない浮動小数点数定数は `float32` に問題なく代入できますが、
そのデフォルト型は `float64` です。

```go
var f32 float32
f32 = 0.0
f32 = Zero      // OK: Zeroは型付けされていない
f32 = TypedZero // ダメ: TypedZeroはfloat64でありfloat32ではない
fmt.Println(f32)
```

浮動小数点数値はオーバーフロー、つまり値の範囲という概念を紹介するのに良い題材です。

数値定数は任意精度の数値空間に存在しています。つまり、それらは単なる普通の数なのです。
しかし、それらがある変数に代入された場合には、その値が代入先に合うようにならなければいけません。
定数で非常に大きな値を宣言することが出来ます。

```go
const Huge = 1e1000
```

これは単なる数字で、それ以外の何者でもありません。しかし、それを代入できませんし、表示することさえできません。
この文はコンパイルすら通りません。

```go
fmt.Println(Huge)
```

エラーは「constant 1.00000e+1000 overflows float64 （定数 1.00000e+1000 は float64 の範囲からオーバーフローしています）」
というもので、これは正しい内容です。しかし、 `Huge` が使える時もあります。それは、他の定数との式の中で使って、
その式の結果が `float64` の範囲内に収まる場合です。次の式を見てください。

```go
fmt.Println(Huge / 1e999)
```

これは `10` を出力します。予想通りです。

同様に、浮動小数点数定数には非常に高い精度を持たせることが出来るので、それが関わる数値計算はより正確になります。
[math](https://golang.org/pkg/math) パッケージで定義されている定数は `float64` で扱える範囲よりも
多くの桁数を持っています。これは `math.Pi` の定義です。

```go
Pi    = 3.14159265358979323846264338327950288419716939937510582097494459
```

この値が変数に代入されたときに、精度がある程度失われます。代入することで元の高精度の値に最も近い
 `float64` （あるいは `float32` ）の値ができます。次のスニペットでは

```go
pi := math.Pi
fmt.Println(pi)
```

`3.141592653589793` が出力されます。

桁数を多く持てることで、 `Pi/2` のような計算やより複雑な評価をする際に結果が代入されるまで、
より高い精度を維持したままでいられます。これによって、定数が関わる計算を精度を失うことなく
書きやすくなっています。また、浮動小数点の無限、アンダーフロー、 `NaN` といったコーナーケースが
定数の式では発生しません。（定数のゼロによる除算はコンパイル時エラーとなり、またすべてが数字の場合には
「not a number」というようなエラーは発生しえません。）

## 複素数
複素数定数は多くの点で浮動小数点数定数と同様に振る舞います。いつもの例を複素数でやってみます。

```go
type MyComplex128 complex128
const I = (0.0 + 1.0i)
const TypedI complex128 = (0.0 + 1.0i)
var mc MyComplex128
mc = (0.0 + 1.0i) // OK
mc = I            // OK
mc = TypedI       // ダメ
fmt.Println(mc)
```

複素数のデフォルト型は `complex128` で、2つの `float64` の値で構成された精度が大きい型です。

曖昧さ回避のためにいうと、例では `(0.0+1.0i)` と完全表記をしていますが、この値は `0.0+1.0i` と短く出来ますし、
さらに言えば `1.0i` あるいは `1i` と書けます。

ちょっと遊んでみましょう。Goでは、数値定数はただの数字だと知っています。もし数字が虚数部がない複素数だった場合に、
つまりそれは実数なのでしょうか。一つ用意してみます。

```go
const Two = 2.0 + 0i
```

これは型付けされていない複素数です。たとえ虚数部がなくても、式の _構文_ がデフォルト型 `complex128` を持つように
定義します。それゆえ、変数宣言にこの定数を使うと、デフォルト型は `complex128` になります。このスニペットは
`complex128: (2+0i)` と出力します。

```go
s := Two
fmt.Printf("%T: %v\n", s, s)
```

しかし数値としては、定数 `Two` は情報を失うことなくスカラーの浮動小数点数、つまり `float64` あるいは `float32` に
保存することが出来ます。したがって、初期化あるいは代入で何も問題なく `Two` を `float64` に代入できます。

```go
var f float64
var g float64 = Two
f = Two
fmt.Println(f, "and", g)
```

出力は `2 and 2` です。たとえ `Two` が複素数定数だとしても、スカラーの浮動小数点数の変数に代入できます。
このように定数が型を「渡り歩く」ことができる機能があることが役立つとわかるでしょう。

## 整数
ついに整数までやってきました。整数には [サイズや符号の有無など](http://golang.org/ref/spec#Numeric_types)
変化する部分がたくさんあります。しかしこれまでと同じ規則に従います。最後にまた、今回は `int` だけを使って
いつもの例を見てみましょう。

```go
type MyInt int
const Three = 3
const TypedThree int = 3
var mi MyInt
mi = 3          // OK
mi = Three      // OK
mi = TypedThree // ダメ
fmt.Println(mi)
```

同じ例は整数型のどの型でも成立します。

```go
int int8 int16 int32 int64
uint uint8 uint16 uint32 uint64
uintptr
```

（上記の型に加えて、 `uint8` のエイリアスの `byte` と `int32` のエイリアスの `rune` も同様です）
とても多くの型がありますが、これまで十分に見てきた定数の振る舞いがここでも当てはまります。

先に述べたように、整数はいくつかの形式で表されますし、それぞれの形式にはそれぞれのデフォルト型があります。
`123` 、 `0xFF` 、 `-14` というような単純な定数は `int` で、 `'a'` 、 `'世'` や `'\r'` というような引用された文字は
`rune` です。

どの定数の形式も符号なし整数型をデフォルト型としては持っていません。しかしながら、型付けされていない定数の柔軟性によって
私たちが型を明確にする限り単純な定数で符号なし整数の変数を初期化できます。これは虚部がゼロの複素数で `float64` の変数を
初期化できることに似ています。次にいくつかの方法で `uint` の変数を初期化する方法を並べます。
これらはすべて等価ですが、結果が符号なしになるように明示的に型を与えなければなりません。

```go
var u uint = 17
var u = uint(17)
u := uint(17)
```

浮動小数点数型の節でふれた値域に関する問題と同様に、すべての整数値がすべての整数型に適用できるわけではありません。
2つの問題が発生しえます。値が大きすぎる、または符号なし整数に負の値が代入されるかの2つです。たとえば、 `int8` は
-128 から 127 の値域があり、この範囲を外れた定数は `int8` 型の変数には決して代入できません。

```go
var i8 int8 = 128 // エラー： 値が大きすぎます。
```

同様に、  `byte` としても使われる `uint8` は、値域が0から255で、これより大きい整数もしくは負の整数は `uint8` 型の変数には代入できません。

```go
var u8 uint8 = -1 // エラー： 負の値。
```

型チェックによりこのような誤りを検出できます。

```go
type Char byte
var c Char = '世' // エラー： '世' の値は 0x4e16 で、大きすぎます。
```

もしコンパイラがあなたの定数の使い方に対して文句を言ってきたら、おそらく今挙げたような間違いに起因する実際のバグでしょう。

## 演習: 最大の符号なし整数

ここで、ちょっとした有益な演習を行ってみましょう。 `uint` の範囲内で最大値の定数を表現できるでしょうか。
もし `uint` ではなく `uint32` であれば、このように書くことが出来ます。

```go
const MaxUint32 = 1<<32 - 1
```

しかし私たちが欲しいのは `uint32` ではなく `uint` です。 `int` 型と `uint` 型は同様に、32ビットか64ビットかといったビット数の指定はありません。
どのビット数が使えるかはアーキテクチャに依存するので、単純に値を書くことは出来ません。

Goの整数が採用すると定められている[2の補数](http://ja.wikipedia.org/wiki/2%E3%81%AE%E8%A3%9C%E6%95%B0)のファンであれば、
`-1` はビットがすべて1となるので、 `-1` のビットパターンは内部的には符号なし整数の最大値と同じになると知っています。
それゆえ、次のように考えてしまいますが、

```go
const MaxUint uint = -1 // エラー: 負の値
```

これは不正となります。なぜなら-1は符号なしの変数では表現しえないからです。
`-1` は符号なしの値の値域にはありません。
同様の理由で、型変換も意味をなしません。

```go
const MaxUint uint = uint(-1) // エラー: 負の値
```

たとえ、実行時に-1の値が符号なし整数に変換出来たとしても、定数の [変換](http://golang.org/ref/spec#Conversions) のルールはコンパイル時にこの種の抜け穴を禁止します。
つまり、次のコードは実行はできますが

```go
var u uint
var v = -1
u = uint(v)
```

これは `v` が変数だからという理由だけです。もし `v` を定数にすると、たとえ型付けされていない定数だとしても、禁止区域に戻ってきてしまいます。

```go
var u uint
const v = -1
u = uint(v) // エラー: 負の値
```

また、先ほどと同様のアプローチに戻ってみます。ただし今回は `-1` の代わりに `^0` 、つまり0のビットの否定（NOT）を使ってみましょう。
この例も同様の理由で失敗します。数値の空間では `^0` は無限数を表すため、固定サイズの整数に代入する際に情報を失ってしまいます。

```go
const MaxUint uint = ^0 // エラー: 桁あふれ
```

ではどのように符号なし整数の最大値を定数で表せばよいのでしょうか。

鍵となるのは、 `uint` 型の変数内のビットに対する操作に制約をかけて、 `uint` で表現できない、たとえば負の数といった値を避ける事です。
最も単純な `uint` 型の値は、型付けされた定数の `uint(0)` です。もし `uint` が32ビットまたは64ビットだった場合、それに応じて
`uint(0)` も32個または64個の0のビットを持つことになります。これらのビットをそれぞれ反転すれば、正しい数の1のビットを持つこととなり、
これが `uint` 型の値の最大値となります。

したがって、型付けされていない定数 `0` のビットを反転するのではなく、型付けされた定数 `uint(0)` のビットを反転するのです。
これで欲しかった定数が得られます。

```go
const MaxUint = ^uint(0)
fmt.Printf("%x\n", MaxUint)
```

現在の実行環境での `uint` を表現するビット数がいくつでも（[playground](http://blog.golang.org/playground) では32ビットです）、
この定数は正しく `uint` 型が持てる最大値を表現しています。

この結果に至るまでの分析を理解すれば、Goでの定数について重要な点を理解したといえるでしょう。

## 数字
Goにおける型付けされていない定数の概念は整数、浮動小数点数、複素数、さらには文字といった数値定数は
すべてある種統一された空間に存在するということを意味しています。それらの定数を変数、代入、演算といった
計算の世界に持ち込んだときに実際の型が関係してきます。しかし、数値定数の世界に留まる限り、
値を混ぜたり合致させたりすることができます。これらの定数はすべて数値 1 を持っています。

```go
1
1.000
1e3-99.0*10-9
'\x01'
'\u0001'
'b' - 'a'
1.0+3i-3.0i
```

したがって、これらは暗黙のデフォルト型を持っていますが、型付けされていない定数として書かれているので、
これらは任意の数値型の変数に代入できます。

```go
var f float32 = 1
var i int = 1.000
var u uint32 = 1e3 - 99.0*10.0 - 9
var c float64 = '\x01'
var p uintptr = '\u0001'
var r complex64 = 'b' - 'a'
var b byte = 1.0 + 3i - 3.0i

fmt.Println(f, i, u, c, p, r, b)
```

この出力は次のようになります。 `1 1 1 1 1 (1+0i) 1`。

こんなおかしなことさえもできます。

```go
var f = 'a' * 1.5
fmt.Println(f)
```

これは145.5を出力しますが、この例は先の話を証明する以外特に意味はありません。


しかし、これらのルールの本当に大事な点は柔軟性です。この柔軟性の意味するところは、
Goでは同じ式の中で浮動小数点数と整数の変数を混ぜること、さらには `int` と `int32` の
変数すら混ぜることは不正ですが、たとえば

```go
sqrt2 := math.Sqrt(2)
```

や

```go
const millisecond = time.Second/1e3
```

あるいは

```go
bigBufferWithHeader := make([]byte, 512+1e6)
```

と書くことは許されていて、あなたの期待するとおりの結果となります。

なぜならGoでは、数値定数はあなたの期待したとおり、つまり数字として動作するからです。

By Rob Pike

