Goは明示するけど全部が手書きではない
:= は型を消す記法ではない
前回 は、fmt.Println と fmt.Printf の違いを整理しました。
Goを触る前は、もっと全部を細かく書く言語なのかなと思っていました。型も全部書いて、メモリも全部自分で考えて、Pythonよりずっと固い、みたいなイメージです。
でも、少し触ると、思ったより柔らかいところもありました。たとえば := です。
name := "kohei"
age := 30
ok := true
これは、関数の中で新しい変数を作る短い書き方です。右側の値から型を推測してくれます。
この短い変数宣言は、Go言語仕様の Short variable declarations(公式)に説明があります。
毎回こう書かなくてもよい、ということですね。
var name string = "kohei"
最初は := を見て、「これは一旦退避する記法なのかな?」と思っていました。でもそうではなく、変数宣言と代入をまとめているだけでした。
既存変数には = を使う
すでにある変数に入れ直すときは = です。
age := 30
age = 31
このあたり、ゆるく見えてちゃんとルールがあります。Pythonほど何でもその場で入れ替えられる感じではないけど、全部を毎回手書きするわけでもない。ここは思っていたより扱いやすそうだなと思いました。
var と const の見方
違いは型指定ではなく変更可否
var と const も、少し勘違いしそうでした。
違いは、型指定が必須かどうかではありません。どちらも型は省略できます。
var x = 10
const y = 10
一番大きい違いは、あとから変更できるかどうかです。
var x = 10
x = 20 // OK
const y = 10
// y = 20 // NG
var は変数、const は定数です。ここまでは分かりやすいです。
const は代入先で解釈されることがある
面白かったのは、Goの const は型なし定数として扱える場合があるところでした。
このあたりは、Go言語仕様の Variables(公式)と Constants(公式)を読むと、ちゃんとした説明に戻れます。
const value = 10
i := value
var f float64 = value
この場合、i は int として扱われ、f は float64 として扱われます。定数の値が、代入先に合わせて解釈される感じです。
Pythonの変数感覚とは少し違う
名前に値を貼り替える感覚ではない
Pythonを書いていると、変数は「名前に値を貼る」くらいの感覚で扱うことが多いです。
value = 10
value = "hello"
これはPythonでは普通に書けます。もちろん、実際には型がなくなるわけではなく、値それぞれには型があります。ただ、コードを書く感覚としては、同じ名前に別の型の値を入れ直すことへの抵抗はかなり小さいです。
Goでは、いったん変数の型が決まると、その変数へ別の型の値をそのまま入れる感じではありません。
value := 10
// value = "hello" // NG
この違いは、最初は少し窮屈に見えました。でもAPIを書くことを考えると、あとから読む人にとってはかなり助かりそうです。
APIの値は途中で姿を変えない方が読みやすい
たとえば、requestから受け取った値を検証して、response用の値へ詰め替える処理を考えます。
このとき、同じ変数名が途中で文字列になったり、数値になったり、構造体になったりすると、追いかける側はかなり大変です。
Goでは、型が決まっていることで「この変数は何を持っているのか」が比較的はっきりします。もちろん命名が悪ければ読みにくいですが、少なくとも同じ変数が途中で別の種類の値へ変わり続ける感じにはなりにくいです。
Pythonで書くときも型ヒントを使えば近いことはできます。ただ、Goの場合は言語の基本の流れとして、変数宣言、代入、型が最初から強く意識されます。
厳しいだけではなかった
必要なところは推測してくれる
型がある言語というと、もっと全部が固定されているイメージがありました。でも、こういうところは思ったより柔軟でした。
:= で右辺から型を推測してくれる。const は代入先に合わせて扱える場合がある。一方で、すでにある変数へ入れ直すときは = を使うし、あとから別の型へ雑に入れ替える感じではない。
厳しいだけではなくて、必要なところは推測してくれる。ここで少しGoの印象が変わりました。
次は Goのsliceで len、cap、copyの感覚を掴む に進みます。