Goクイズアドベントカレンダー19日目
December 19, 2020
この記事は、Goクイズ Advent Calendar 2020の19日目の記事です。
問題
以下のコードを実行するとどうなるか?
package main
import _ "fmt"
var x T; type T int; type _ T; type _ = T; const _ = 0
var _ = func(_ T) (_ T) { x++; return }
func (_ T) _(_ T) (_, _, _ T) { return }
var _ = func(T,_ T) (_ T) { x++; return }(x,x)
func main() { fmt.Println(x) }
func (_ T) _(_ T) (_, _, _ T) { return }
func _() {}
- コンパイルエラー
0
と表示される1
と表示される2
と表示される
解答と解説
答えは「1. コンパイルエラー」でした!
解答
これは、以下のように_
がどこまで使えるのかということを問う問題です。
- インポート文で使えるか
- 型定義で使えるか
- 型エイリアスで使えるか
- 定数定義で使えるか
- 変数定義で使えるか
- 関数の引数や戻り値に使えるか
- 関数名に使えるか
解説
_
はブランク識別子と呼ばれ、変数への代入などを省略したい場合に使用します。主に代入文の左辺(参照)に使われ、右辺(値)として使用することはできません。
代入文の他にも、何かしらの定義において識別子として使えます。例えば、型定義、型エイリアス、定数定義、変数定義、関数定義などです。また、関数定義については引数や戻り値だけではなく関数名にも使えます。もちろん、メソッドにも使えます。
なお、ブランク識別子は何度使用しても定義済み識別子のコンパイルエラーにはなりません。そのため、_
関数や_
メソッドを複数定義することも可能です。
では、なぜコンパイルエラーになるのか?
さて、答えはコンパイルエラーになります。ブランク識別子を使ってパッケージをインポートした場合、そのパッケージは別途インポートしない限り(ブランク識別子を使用せず)はファイル内で使用することはできません。
問題のfmt
パッケージは、ブランク識別子を使ってインポートされているため、fmt.Println
関数は使用できません。つまり、コンパイルエラーになります。
なお、ブランク識別子を使ったパッケージのインポートは、init
関数における副作用を期待する場合に用います。database/sql
パッケージやimage
パッケージを用いる場合に、ドライバーや画像形式を登録する場合に用いることが多いでしょう。