Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1475] ファイルの概要

このコミットは、Go言語における定数(const)の型推論と型変換に関する重要な挙動をテストするために追加されたものです。具体的には、明示的な型(例: uint64)が指定された定数が、抽象的な型(untyped constant)として扱われないことを検証するテストケースが導入されました。これにより、Goコンパイラが定数の型を正しく解釈し、予期せぬ型変換エラーを防ぐための基盤が強化されています。

コミット

commit c0f6144f1b20d3805ee47781dc9683f6d302192c
Author: Ian Lance Taylor <iant@golang.org>
Date:   Thu Jan 15 11:23:35 2009 -0800

    Test that a const with an explicit type is not treated as
    having an abstract type.
    
    R=gri
    DELTA=11  (11 added, 0 deleted, 0 changed)
    OCL=22829
    CL=22832
---
 test/bugs/bug131.go | 12 ++++++++++++\n test/golden.out     |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/test/bugs/bug131.go b/test/bugs/bug131.go
new file mode 100644
index 0000000000..96e7cc7647
--- /dev/null
+++ b/test/bugs/bug131.go
@@ -0,0 +1,12 @@
+// errchk $G $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+  const a uint64 = 10;
+  var b int64 = a;
+}
diff --git a/test/golden.out b/test/golden.out
index a74d96bcd4..326327bbc1 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -143,6 +143,9 @@ BUG129
 bugs/bug130.go:14: fatal error: getoutarg: not a func RANGE
 BUG: should run
 
+=========== bugs/bug131.go
+BUG: should not compile
+
 =========== fixedbugs/bug016.go
 fixedbugs/bug016.go:7: overflow converting constant to uint
 

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/c0f6144f1b20d3805ee47781dc9683f6d302192c

元コミット内容

Test that a const with an explicit type is not treated as having an abstract type.

(明示的な型を持つ定数が、抽象的な型として扱われないことをテストする。)

変更の背景

Go言語では、定数には「型なし定数(untyped constant)」と「型付き定数(typed constant)」の概念があります。型なし定数は、その値が表現できる任意の数値型に暗黙的に変換できる柔軟性を持っています。例えば、const x = 10x は型なし定数であり、intfloat64complex128 など、様々な数値型の変数に代入できます。

しかし、const a uint64 = 10 のように明示的に型が指定された定数は、その指定された型(この場合は uint64)を持つべきです。もしコンパイラがこのような明示的な型を持つ定数を誤って型なし定数として扱ってしまうと、予期せぬ型変換(例えば、uint64 から int64 への直接代入)が許可されてしまい、符号付き整数と符号なし整数の間の変換で値の解釈が変わり、バグを引き起こす可能性があります。

このコミットは、このような潜在的なバグを防ぐために、明示的な型を持つ定数が正しくその型として扱われ、型なし定数のような柔軟な暗黙的変換が適用されないことを保証するためのテストを追加しています。これにより、Go言語の型安全性と予測可能性が向上します。

前提知識の解説

Go言語の定数(Constants)

Go言語の定数は、プログラムの実行中に値が変わらない不変のエンティティです。定数は const キーワードを使って宣言されます。

  1. 型なし定数 (Untyped Constants):

    • 型が明示的に指定されていない定数です。
    • 例: const x = 10
    • これらの定数は、その値が表現できる任意の数値型に暗黙的に変換できます。これは、コンパイル時にその値が特定の型に「固まっていない」ため、より柔軟な利用が可能です。
    • 例えば、intfloat64complex128 など、異なる型の変数に代入しても、コンパイラが適切な型に変換を試みます。
  2. 型付き定数 (Typed Constants):

    • 型が明示的に指定されている定数です。
    • 例: const a uint64 = 10
    • これらの定数は、宣言時に指定された特定の型を持ちます。型なし定数のような柔軟な暗黙的変換は適用されず、通常の変数と同様に厳密な型チェックが行われます。
    • 異なる型への代入や演算には、明示的な型変換(キャスト)が必要になる場合があります。

Go言語の型変換(Type Conversion)

Go言語は静的型付け言語であり、異なる型の間の代入や演算には厳密なルールがあります。

  • 暗黙的な型変換: Goでは、基本的に異なる型間の暗黙的な型変換は行われません。ただし、型なし定数から型付き変数への代入など、一部の例外があります。
  • 明示的な型変換(キャスト): 異なる型間で値を変換するには、T(v) のように明示的に型を指定する必要があります。例: var i int = int(f)

uint64int64

  • uint64: 64ビットの符号なし整数型です。0から約1.84 × 10^19までの正の整数を表現できます。
  • int64: 64ビットの符号付き整数型です。約-9.22 × 10^18から約9.22 × 10^18までの整数を表現できます。

これらの型はビット幅は同じですが、表現できる値の範囲と解釈が異なります。特に、uint64 の最大値は int64 の最大値の約2倍であり、負の値を表現できません。そのため、uint64 から int64 への直接的な代入は、値の範囲外になる可能性や符号の解釈が変わる可能性があるため、通常は明示的な型変換が必要です。

技術的詳細

このコミットで追加された test/bugs/bug131.go のテストケースは、Goコンパイラが明示的な型を持つ定数をどのように扱うかを検証しています。

func main() {
  const a uint64 = 10;
  var b int64 = a;
}

ここで重要なのは、const a uint64 = 10; の行です。 auint64 という明示的な型が与えられた定数です。したがって、auint64 型の定数として扱われるべきであり、型なし定数のような振る舞い(例えば、int64 型の変数 b に直接代入できるような暗黙的な変換)は許されるべきではありません。

もしコンパイラが a を誤って型なし定数として扱ってしまうと、10 という値は int64 の範囲内であるため、var b int64 = a; という代入が成功してしまう可能性があります。しかし、auint64 型であるため、uint64 から int64 への代入は、Goの厳密な型チェックルールに基づけば、明示的な型変換なしには許可されるべきではありません。

このテストケースは、この代入がコンパイルエラーになることを期待しています。test/golden.outBUG: should not compile と追記されていることからも、このコードがコンパイルエラーになることが正しい挙動であるとされています。

これは、Go言語の設計思想である「明示的な型付けと厳密な型チェック」を反映しています。型なし定数は柔軟性を提供しますが、明示的に型が指定された定数は、その型に厳密に従うことで、予期せぬバグやデータ損失を防ぎ、コードの安全性を高めます。このコミットは、コンパイラがこの重要な区別を正しく実装していることを確認するためのものです。

コアとなるコードの変更箇所

このコミットでは、以下の2つのファイルが変更されています。

  1. test/bugs/bug131.go (新規追加)

    • Go言語のテストケースファイルです。
    • 明示的な型を持つ定数と、異なる符号付き整数型への代入に関する挙動をテストするコードが含まれています。
  2. test/golden.out (変更)

    • Go言語のテストスイートにおける期待される出力(エラーメッセージなど)を記録するファイルです。
    • test/bugs/bug131.go のテストがコンパイルエラーになることを示すエントリが追加されています。

コアとなるコードの解説

test/bugs/bug131.go

// errchk $G $D/$F.go

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

func main() {
  const a uint64 = 10;
  var b int64 = a;
}
  • // errchk $G $D/$F.go: これはGoのテストフレームワークで使用されるディレクティブで、このファイルがコンパイルエラーを生成することを期待していることを示します。$G はGoコンパイラ、$D/$F.go は現在のファイルのパスを指します。
  • const a uint64 = 10;: ここで a という定数が宣言されています。重要なのは、uint64 という明示的な型が与えられている点です。これにより、auint64 型の定数となり、型なし定数のような振る舞いはしません。
  • var b int64 = a;: ここで b という int64 型の変数が宣言され、a の値が代入されようとしています。
    • auint64 型であり、bint64 型です。Go言語では、異なる数値型(特に符号付きと符号なし)の間で明示的な型変換なしに直接代入することは許可されていません。
    • もし a が型なし定数であれば、10 という値は int64 の範囲内であるため、この代入は成功する可能性があります。しかし、auint64 型であるため、この代入はコンパイルエラーになるべきです。

このテストケースは、var b int64 = a; の行でコンパイルエラーが発生することを期待しており、これにより、明示的な型を持つ定数が正しくその型として扱われていることを検証します。

test/golden.out の変更

+=========== bugs/bug131.go
+BUG: should not compile
  • =========== bugs/bug131.go: これは、test/bugs/bug131.go のテスト結果に関するセクションの開始を示します。
  • BUG: should not compile: この行は、test/bugs/bug131.go がコンパイルエラーになることが期待されることを明示しています。これは、Goコンパイラが uint64 型の定数を int64 型の変数に暗黙的に代入しようとする試みを正しく拒否することを確認するためのものです。

これらの変更は、Go言語の型システムが、定数の型指定に関して厳密かつ予測可能な挙動をすることを保証するために不可欠です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコードリポジトリ (特に test/bugs ディレクトリ内の他のテストケース)
  • Go言語の型システムに関する一般的な解説記事