Shogo's Blog

Nov 22, 2018 - 2 minute read - go golang

Goのnil,true,falseは変数名に使えるという話

@Linda_pp さんのツイートをみて

なるほど、これは面白い。 と少し遊んでみたメモ。


言語仕様にある通り、Goのキーワードは以下の25個です(Go1.11.2)。

break        default      func         interface    select
case         defer        go           map          struct
chan         else         goto         package      switch
const        fallthrough  if           range        type
continue     for          import       return       var

この一覧に niltrue, false は入っていません。 これらは builtinという扱いになっており、識別子として利用可能です。

そのため、変数名等に利用可能というわけですね。面白い。

package main

import (
	"fmt"
)

func main() {
	nil := 42
	fmt.Println(nil)
	// Output:
	// 42
}

以下、色々遊んでみた例。

組み込みの型である int も識別子として利用可能。

package main

import (
	"fmt"
)


func main() {
	int := 42
	fmt.Println(int)
	// Output:
	// 42
}

truefalse を入れ替えることができる。

package main

import (
	"fmt"
)

func main() {
	true, false := false, true
	fmt.Println(true, false)
	// Output:
	// false true
}

Go 1.9 で追加された Type Alias を使えば、組み込みの型を上書きすることだって可能。便利(?)

package main

import (
	"fmt"
)

type int = float64

func main() {
	var i int
	fmt.Printf("%T", i)
	// Output:
	// float64
}

考察

@Linda_pp さんがGitHubに突撃してくれました。(この行動力すごい。自分は英語書く時点でギブアップ・・・)

すぐに返事が来て、「これは意図したもので、キーワードではなく事前定義された識別子(predeclared identifier)」とのこと。

:thinking_face:

自分なりに誰が得するのか考えてみたんですが、後方互換性を保つために、キーワードをなるべく増やしたくない・・・とか?

例えば、最近 Python 3.7 にasync/await が新キーワードとして追加され、互換性が壊れたと少し話題になってましたね。

このように、言語仕様に新しいキーワードを追加することは、容易に互換性を壊してしまします。

「事前定義された識別子」の追加であれば、万が一既存のコードと識別子がかぶってしまっても、正しくコンパイルすることができます。 例えば、最初に書いたこのコード、 nil が事前定義された識別子であっても、そうでなくても、同じ挙動になります。 nil がキーワードだったら、このコードはコンパイルできなくなってしまいます。

package main

import (
	"fmt"
)

func main() {
	nil := 42
	fmt.Println(nil)
	// Output:
	// 42
}

というわけで、この仕様はなるべく互換性を崩さない工夫なのかなあ、というのが僕の結論です。 何か他にご意見のある方は golang-nuts mailing list へどうぞ!!