Goクイズ
Goクイズとは、プログラミング言語Goに関するクイズです。プログラムを見て実行結果を予想します。文法などのGoに関する知識が問われます。4択などの選択式であることが多いでしょう。
@mercaridevjpのTwitterアカウントでも以下のような問題をポストしました!
問題
以下のコードを実行するとどうなるか?
package main
func main() {
true := false
println(true == false)
}
- コンパイルエラー
- trueと表示される
- falseと表示される
- パニックが発生する
Twitterでのみなさんの回答
Twitterの投票機能を使って、みなさんの回答を集めてみました。結果は以下のようになりました。
「コンパイルエラー」と「trueと表示される」が多くて、後者が若干上回っています。
回答と解説
答えは「trueと表示される」です!
この問題はtrue := false
がコンパイルエラーになるのか、ならない場合はどうなるのか?ということが論点になります。
Goでは変数名(識別子)には、if
やtype
などの予約語は使えません。そのため、true
が予約語である場合はコンパイルエラーになります。しかし、true
は言語仕様によるとユニバースブロックで事前定義された名前付き定数となっています。
Goでは以下のように外のブロックで定義された変数名と同じ名前の変数を内側のブロックで定義することが可能です。main
関数の最初のprintln
関数はパッケージ変数x
の値である100
を表示します。しかし、2つめのprintln
関数は、直前で定義されたローカル変数x
の値である"hello"
を表示します。
なお、ここでは変数について説明しましたが、基本的には名前付き定数など識別子(名前)を伴うものは同じような挙動になります。
package main
var x int = 100
func main() {
println(x) // 100と表示される
var x string = "hello"
println(x) // helloと表示される
}
さて、true
の場合を考えてみましょう。true
はユニバースブロックで定義された名前付き定数でした。ユニバースブロックとは、すべてのスコープの親(ルート)となるようなスコープです。そのため、そこで定義された識別子(名前)と同じ名前で子スコープ(それ以下も含む)となる任意のスコープで定義することが可能です。
つまり、問題にあるtrue := false
は、main
関数のスコープで新しい変数true
を作り、そこにユニバースブロックで定義された名前付き定数false
の値を代入するという事になります。ちなみに、このときtrue = false
と書くと変数定義ではなく、ただの代入になるので、定数への代入はできないためコンパイルエラーになります。
そして、println(true == false)
は、値が真偽値のfalse
(偽)である変数true
と、同じく値が真偽値のfalse
(偽)であるユニバースブロックで定義された名前付き定数false
の比較であるため、真偽値のtrue
(真)になります。そのため、最終的にはtrue
が表示されます!
ユニバースブロックで定義された識別子と同じ識別子が定義できることが分かると以下のようなコードも書けます。面白いですね!!
package main
func main() {
type string int
var s string
println(s + 10) // 10と表示される
}
もっとクイズをやってみたい方へ
今回のGoクイズを解いたり回答を見て、「へぇー!こんな風に書けるんだ!」と感じた方もいるのではないでしょうか。そんな方には、「開発ライブ実況 #7 あるあるバグを仕込んだ渾身のGoクイズを持ち寄って出し合います!」というイベントがオススメです!
Goの言語仕様に詳しい社内外のGopher4人が集まり、渾身のGoクイズを出し合います。もちろん、出題者からの解説とともに日頃の開発で活きるハマリポイントなども聞けるでしょう。
練習問題も用意してますので、ぜひウォーミングアップも兼ねてチャレンジしてみてください!
@mercaridevjpのTwitterアカウントでも引き続き問題を投稿していきますので、ぜひフォローしてお待ち下さい!
問題を解くだけじゃ足りない!!自分も作ってみたいぞ!って方は、ぜひGoクイズ アドベントカレンダーにご参加ください!