コンテンツにスキップ

Go/定数と変数

出典: フリー教科書『ウィキブックス(Wikibooks)』
< Go

定数

[編集]

定数には、真偽値定数、ルーン定数、整数定数、浮動小数点定数、複素数定数、文字列定数があります。ルーン定数、整数定数、浮動小数点定数、複素数定数を総称して数値定数と呼びます[1]

定数値は、ルーン、整数、浮動小数点、虚数、文字列リテラル、定数を示す識別子、定数式、結果が定数となる変換、あるいは、unsafe.Sizeof関数を任意の値に、capやlenをいくつかの式に、realやimagを複素数定数に、complexを数値定数に適用するなど、いくつかの組み込み関数の結果値で表されます。真偽値は、事前に宣言された定数trueとfalseで表されます。宣言済み識別子 iota は、整数定数を表します。

一般に、複素数定数は定数表現の一形態であり、定数式の項で説明します。

数値定数は、任意の精度の正確な値を表し、オーバーフローしません。そのため、IEEE-754の負のゼロ、無限大、および数字ではない値を表す定数はありません。

定数には、型付きのものと型無しのものがあります。リテラル定数、true、false、iota、および型付けされていない定数オペランドのみを含む特定の定数式は、型付けされていません。

定数は、定数宣言や変換によって明示的に型が与えられる場合と、変数宣言や代入、式のオペランドとして使用される場合に暗黙的に型が与えられる場合があります。定数の値がそれぞれの型の値として表現できない場合はエラーになります。

型付けされていない定数には、デフォルトの型があります。これは、型付けされた値が必要とされる文脈、例えば、i := 0のように明示的な型がない短い変数宣言の中で、定数が暗黙的に変換される型です。型付けされていない定数のデフォルトの型は、bool、rune、int、float64、complex128、stringのいずれであるかに応じて、それぞれ異なります。

実装上の制約。数値定数は言語上では任意の精度を持っていますが、コンパイラは精度が制限された内部表現を使って実装することができます。とはいえ、すべての実装は以下のようにしなければなりません。

  • 整数定数を 256 ビット以上で表現する
  • 複素数定数の一部を含む浮動小数点定数を、256ビット以上の仮数と16ビット以上の符号付き2進指数で表現する
  • 整数定数を正確に表現できない場合はエラーとする
  • オーバーフローのために浮動小数点または複素数の定数を表すことができない場合は、エラーとする
  • 精度に制限があるために浮動小数点または複素数の定数を表現できない場合は、表現可能な最も近い定数に丸める

これらの要件は、リテラル定数にも、定数式の評価結果にも適用されます。

定数宣言

[編集]

定数宣言(A constant declaration)は、識別子のリスト(定数の名前)を定数式のリストの値に結びつける(binds)ものです。識別子の数は式の数と等しくなければならず、左からn番目の識別子は右からn番目の式の値に束縛(bound)されます[2]

構文
ConstDecl      = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) ;
ConstSpec      = IdentifierList [ [ Type ] "=" ExpressionList ] ;

IdentifierList = identifier { "," identifier } ;
ExpressionList = Expression { "," Expression } ;

型のある場合、すべての定数は指定された型を取り、式はその型に割り当て可能でなければなりません。型が省略された場合、定数は対応する式の個々の型を取ります。式の値が型付けされていない定数である場合、宣言された定数は型付けされていないままであり、定数の識別子が定数の値を表します。例えば、式が浮動小数点リテラルの場合は、リテラルの小数部がゼロであっても、定数識別子は浮動小数点定数を表します。

const Pi float64 = 3.14159265358979323846
const zero = 0.0 // 型付けされていない浮動小数点定数
const (
        size int64 = 1024
        eof        = -1 // 型付けされていない整数定数
)
const a, b, c = 3, 4, "foo" // a = 3, b = 4, c = "foo", 型付けされていない整数お
  び文字列定数
const u, v float32 = 0, 3   // u = 0.0, v = 3.0

括弧付きの const 宣言リストの中では、最初の ConstSpec 以外は式リストを省略することができます。このような空のリストは、最初の先行する空でない式のリストと、もしあればその型をテキストで置換することと同じです。したがって、式のリストを省略することは、前のリストを繰り返すことと同じです。識別子の数は、前のリストの式の数と等しくなければなりません。iota定数ジェネレータと一緒に使うと、このメカニズムは、連続した値の軽量な宣言を可能にします。

括弧付きの const 宣言リスト
const (
	Sunday = iota
	Monday
	Tuesday
	Wednesday
	Thursday
	Friday
	Partyday
	numberOfDays  // this constant is not exported
)

iota

[編集]

定数宣言の中で、宣言済み識別子 iota は、連続する型付けされていない整数定数を表します。その値は、定数宣言内のそれぞれのConstSpecのインデックスで、ゼロから始まります。この識別子は、関連する定数のセットを構築するために使用できます[3]

iotaを伴ったconst 宣言リスト
const (
	c0 = iota  // c0 == 0
	c1 = iota  // c1 == 1
	c2 = iota  // c2 == 2
)

const (
	a = 1 << iota  // a == 1  (iota == 0)
	b = 1 << iota  // b == 2  (iota == 1)
	c = 3          // c == 3  (iota == 2は使用しない)
	d = 1 << iota  // d == 8  (iota == 3)
)

const (
	u         = iota * 42  // u == 0     (型のない整数定数)
	v float64 = iota * 42  // v == 42.0  (float64 定数)
	w         = iota * 42  // w == 84    (型のない整数定数)
)

const x = iota  // x == 0
const y = iota  // y == 0

定義によると、同じConstSpec内でiotaを複数回使用すると、すべて同じ値になります。

同じConstSpec内でiotaを複数回使用
const (
	bit0, mask0 = 1 << iota, 1<<iota - 1  // bit0 == 1, mask0 == 0  (iota == 0)
	bit1, mask1                           // bit1 == 2, mask1 == 1  (iota == 1)
	_, _                                  //                        (iota == 2は使用しない)
	bit3, mask3                           // bit3 == 8, mask3 == 7  (iota == 3) 
)

この最後の例は、最後の空でない式のリストの暗黙の繰り返しを利用しています。

変数

[編集]

変数(A variable)とは、値を保持するための記憶場所のことです。許容される値のセットは、変数の型によって決まります[4]

変数宣言(A variable declaration)や、関数の仮引数(function parameters)や戻値(results)の場合は、関数宣言(a function declaration)や関数リテラル(function literal)のシグネチャ(the signature)が、名前の付いた変数のストレージを確保します。組み込み関数newを呼び出したり、複合リテラルのアドレスを取得したりすると、実行時に変数の格納場所が確保されます。このような匿名変数は、(おそらく暗黙の)ポインタ間接(pointer indirection)によって参照されます。

配列型、スライス型、構造体型の構造化変数は、個別にアドレスを指定できる要素やフィールドを持っています。このような要素は、それぞれ変数のように動作します。

変数の静的な型(または単に型)は、その宣言で与えられた型、新規呼び出しまたは複合リテラルで提供された型、または構造化変数の要素の型です。これは、実行時に変数に代入される値の具体的な型です(ただし、宣言済みの識別子であるnilは型を持ちません)。動的型は実行中に変化する可能性がありますが、インターフェイス変数に格納された値は常に変数の静的型に割り当てられます。

var x interface{}  // x is nil and has static type interface{}
var v *T           // v has value nil, static type *T
x = 42             // x has value 42 and dynamic type int
x = v              // x has value (*T)(nil) and dynamic type *T
var x interface{}  // x は値が nil で、静的型 interface{} を持つ
var v *T           // v は値が nil で、静的な型 *T を持つ
x = 42             // x は値が 42 で、動的型 int を持つ
x = v              // x は値 (*T)(nil) と動的型 *T を持つ

変数の値(A variable's value)は、式の中でその変数を参照することで取得され、その変数に割り当てられた最新の値となります。変数にまだ値が割り当てられていない場合、その値はその型のゼロ値となります。

変数宣言

[編集]

変数宣言では、1つまたは複数の変数を作成し、対応する識別子を結合し、それぞれに型と初期値を与えます[5]

構文
VarDecl     = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) ;
VarSpec     = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) ;
var i int
var U, V, W float64
var k = 0
var x, y float32 = -1, -2
var (
	i       int
	u, v, s = 2.0, 3.0, "bar"
)
var re, im = complexSqrt(-1) 
var _, found = entries[name]  // マップ検索、"found "にのみ興味あり

式のリストが与えられた場合、変数は代入のルールに従って式で初期化されます。それ以外の場合、各変数はゼロ値に初期化されます。

型が指定されている場合、各変数はその型で初期化されます。 それ以外の場合は、各変数には、割り当てられた対応する初期化値の型が与えられます。 その値が型付けされていない定数であれば、まずデフォルトの型に暗黙的に変換され、型付けされていない真理値であれば、まず論理型(bool)に暗黙的に変換されます。 型が明示されていない変数の初期化に、宣言済みの値であるnilを使用することはできません。

var d = math.Sin(0.5)  // d は float64
var i = 42             // i は int
var t, ok = x.(T)      // t は T, ok は bool
var n = nil            // 違法

実装上の制限:コンパイラーは、変数が使用されない場合に、関数本体内で変数を宣言することを違法とする場合があります。

短い変数宣言

[編集]

短い変数宣言(A short variable declaration)の構文[6]

構文
ShortVarDecl = IdentifierList ":=" ExpressionList ;
i, j := 0, 10
f := func() int { return 7 }.
ch := make(chan int)
r, w, _ := os.Pipe() // os.Pipe()は、接続されたFilesのペアと、エラーがあればそれを返します。
_, y, _ := coord(p)  // coord()は3つの値を返しますが、y座標にのみ興味があります。

再宣言

[編集]

通常の変数宣言とは異なり、短い変数宣言では、同じブロック(ブロックが関数本体の場合は仮引数リスト(the parameter lists))内で同じ型で以前に宣言された変数を再宣言(redeclare)することができ、空白ではない変数のうち少なくとも1つは新しいものです[6]。 そのため、再宣言は複数変数の短い宣言の中でのみ行われます。再宣言は新しい変数を導入するものではなく、元の変数に新しい値を割り当てるだけです。

field1, offset := nextField(str, 0)
field2, offset := nextField(str, offset) // オフセットの再宣言
a, a := 1, 2 // 違法:aの二重宣言、またはaが別の場所で宣言されていた場合、新しい変数がない。

短い変数宣言は、関数内でのみ使用できます。"if"、"for"、"switch" 文の初期化子など、いくつかの文脈では、ローカルな一時変数を宣言するために使用することができます。

脚註

[編集]
  1. ^ “Constants ¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Constants. 
  2. ^ “Constant_declarations¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Constant_declarations. 
  3. ^ “Iota¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Iota. 
  4. ^ “Variables¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Variables. 
  5. ^ “Variable declarations ¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Variable_declarations. 
  6. ^ 6.0 6.1 “Short variable declarations¶”. The Go Programming Language Specification. The Go website. (Jul 26, 2021). https://golang.org/ref/spec#Short_variable_declarations.