1. エラー文が分かりやすい
var message int = "Hello, Qiita!"
prinln(message)
このコードでは、誤った箇所を2つ残したまま実行しました。
- 変数messageの型
- printlnをprinlnとタイポ
その、実行結果が以下です。
# command-line-arguments
user/main.go:5: cannot use "Hello, Qiita!" (type string) as type int in assignment
user/main.go:8: undefined: prinln
なんと、2つともエラー箇所として、エラー文に反映されています。
そして、エラー文も丁寧!
「Hello, Qiita!」ってそれ、string型じゃね?とまで言ってくれます。
2. 変数再代入の際、型が違うとエラーになる
$a = 1;
var_dump($a);
$a = "aaa";
var_dump($a);
$aに1を代入して出力。
さらに、$aに"aaa"を再代入して、再出力した場合…
int(1)
string(3) "aaa"
しかし、Goだと…
b := 2
println(a)
b = "bbb"
println(b)
# command-line-arguments
./Main.go:6:9: cannot use "bbb" (type string) as type int in assignment
型が違うので、再代入できないとのこと。厳格です。
3. 複数の変数を、同時にコンソール出力できる
a := 1
b := 2
c := 3
println(a,b,c) // => 1 2 3
PHPでデバッグしようとした場合、「var_dump」を書きまくるのはあるあるかと思いますが、Goだとめっちゃ簡単。
これで、書きまくった後の消し忘れも心配ない…笑
ちなみに、JavaScriptは同じことが可能です。
var a = 1;
var b = 2;
var c = 3;
console.log(a,b,c); // => 1 2 3
4. 使わない変数があればエラーになる
JavaScriptやPHPでは
var a = 1;
var b = 2;
console.log(a);
$a = 1;
$b = 2;
var_dump($a);
というコードはなんでもないことですが、
a := 1
b := 2
println(a) // => ./main.go:3:5: b declared and not used
Goだとこのようなエラーが出ます。
「変数b使ってねぇぞ」とのこと。
これは、潜在的なバグを無くすための仕様だそうです。
開発時は、変数の仕様を無視して進めがちなので、注意が必要です。
5. if文の三項演算子や省略形が使えない
残念ながらGoでは、PHPやJavaScriptではよく出てくる、if文の省略形や、三項演算子が使えません。
score := 100
score > 80 ? println("合格!") : ""
// => エラー
score := 100
if score > 80 println("合格!")
// => エラー
score := 100
if score > 80 {
println("合格!")
}
// => 合格!
これも可読性を上げるためみたいですが、…こうなると逆に読みにくいのでは…?なんて思います。笑
6. 「null」ではなく「nil」
…これ、なんか慣れるまで「null」って書いてしまいそうです。笑
「null」ではないので、ご注意を!
7. ポインタの利用
入門したところで、理解が乏しいかと思いますが、Golangは変数のアドレスが確認できるようです。
ちょっと使い所が分かりませんが、おそらく学習を進めていくと、変数のアドレスが必要になることがあるのでしょう…
とりあえず、PHPやJavaScriptにはない概念ですので、サンプルコードだけ載せておききます。
package main
import "fmt"
func main() {
a := 5
var pa *int
pa = &a
fmt.Println(pa) // => 0xc0000140c0
fmt.Println(*pa) // => 5
}
ちなみに、好奇心で試したらこれでもできました。
普通こんな書き方はしないのかもですが…
package main
import "fmt"
func main() {
a := 5
pa := &a
fmt.Println(pa) // => 0xc0000140c0
fmt.Println(*pa) // => 5
}
8. 関数の返り値には型指定が必須
package main
import "fmt"
func hi(name string) string{
msg := "hi!" + name + "さん!"
return msg
}
func main() {
fmt.Println(hi("maeda"))
}
この関数は単純で、hi関数の中でmsg変数を宣言・確認し、returnしてます。
基本的な書き方は、PHPやJavaScriptと似てますが、1つだけやたらに異彩を放っている部分があります。
そうです。
func hi(name string) string{
この、引数の後ろのstring型です。
実はこれ、返り値の型指定を行っているそうです。
なんでこんなところ…
ちなみに、この型指定をしないで実行すると、
./test.go:6:2: too many arguments to return
have (string)
want ()
./test.go:10:16: hi("maeda") used as value
このような、エラーが出ます。
「返す引数が多いよ。ほら、引数は1個のはずなのに、返りの方は0個だ。」的な感じです。
9. 1つの関数内で2つ以上の値をreturnできる
以下は、2つの引数の値を、反対にして返している処理です。
package main
import "fmt"
func swap(a, b int) (int, int) {
return b, a
}
func main() {
fmt.Println(swap(1, 2))
}
// => 2 1
これは、すごい画期的!
PHPやJavaScriptなら、
「一度、引数の値2つを配列化させて、それを一旦返して…」みたいなことになりがちですが、Goだとめちゃめちゃ簡単です。
ちなみに、3つ以上もいけました。
package main
import "fmt"
func swap(a, b, c int) (int, int, int) {
return c, a, b
}
func main() {
fmt.Println(swap(1, 2, 3))
}
// => 3 1 2
10. 配列の宣言・代入がなんかややこしい
たとえばPHPの場合、
$a = [10, 20, 30];
PHPの場合は。宣言らしい宣言不要で、[]
とか古い形式だとarray()
で囲ってやると、簡単に配列に代入できました。
非常に分かりやすい。
JavaScriptでも、はじめに「let」や「const」、「var」がつくだけで、基本的に同じです。
しかし、Goだと
a := [...]int{10, 20, 30}
となる。なんか、多いですね。
しかし実はこれ、
a := [3]int{10, 20, 30}
↑これの省略形で、さらにこれは、
var a[3]int
a[0] = 10
a[1] = 20
a[2] = 30
↑これの省略形だそうです。
Goでの配列は、原則として、宣言時に配列の個数を指定しておく必要があるということですね。
ちなみに、一度配列の個数が決まったのに、後から強引に入れようとすると…
package main
import "fmt"
func main() {
a := [...]int{1, 2, 3} // 配列aは3つと指定されるのに…
a[3] = 40 // 無理やり4つめに代入してみると…
fmt.Println(a)
}
# command-line-arguments
./test.go:6:3: invalid array index 3 (out of bounds for 3-element array)
「配列のインデックス3が無効だよ。」とこれまた丁寧なエラー文がでます。
やはり、ここでも厳格なイメージ。
11. 配列ではなく、スライスを使う
PHPでは特に、配列を扱いやすい便利なメソッドが多く、とりあえず配列にして…みたいな処理にしがちです。
しかしGoでは、違うそうです。
たとえば
package main
import "fmt"
func main() {
a := [...]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90, ..., 10000} // 「a[1000] = 10000」まであるとする
fmt.Println(a[5]) // => 50
fmt.Println(a[6]) // => 60
fmt.Println(a[7]) // => 70
}
↑このようにした場合、
配列aには1000個の値が入っており、a[5]、a[6]、a[7]
と3回呼び出すことで、これら1000個の値を3回使うことになります。
Goでは、この非効率をよしとしないんですね。
なので、Go言語では配列の一部または全部を切り出した、スライスという参照型のデータをよく使うそうです。
- 配列をスライスして、使う部分だけ切り出しておく。
- 切り出した値を使って、処理を行うので、使わない値を持たなくて良い。
ということです。
package main
import "fmt"
func main() {
a := [...]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90, ..., 10000} // 「a[1000] = 10000」まであるとする
s := a[5:8] // => [50, 60, 70]にスライス。値は3つしかない状態に。
fmt.Println(s[0]) // => 50
fmt.Println(s[1]) // => 60
fmt.Println(s[2]) // => 70
}
これによって、先ほどは1000個の値を3回使っていましたが、今回は3個の値を3回使うだけで済んだため、メモリの節約ができました。
12.連想配列ではなく、mapというものを使う
Goでは、キーと値のペアで管理する方法を、mapというものを使って行う。
宣言の仕方等は、こちらで詳しく書いてます。
さいごに
最後まで読んでいただき、ありがとうございました。
まだまだペーペーながら、PHPやJSの常識で新しいことを学ぶと面白いですね。
また、間違えているところ等あればご連絡頂けると幸いです。
最後までありがとうございました。