0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Golang]入門してみて驚いた、PHPやJSとの違い12選

Last updated at Posted at 2019-08-03

1. エラー文が分かりやすい

Go:誤ったコード
var message int = "Hello, Qiita!"
prinln(message)

このコードでは、誤った箇所を2つ残したまま実行しました。

  1. 変数messageの型
  2. 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. 変数再代入の際、型が違うとエラーになる

PHP:型の違う値を変数に再代入
$a = 1;
var_dump($a);
$a = "aaa";
var_dump($a);

$aに1を代入して出力。
さらに、$aに"aaa"を再代入して、再出力した場合…

PHP:実行結果
int(1)
string(3) "aaa"

しかし、Goだと…

Go:型の違う値を変数に再代入
b := 2
println(a)
b = "bbb"
println(b)
Go:実行結果
# command-line-arguments
./Main.go:6:9: cannot use "bbb" (type string) as type int in assignment

型が違うので、再代入できないとのこと。厳格です。

3. 複数の変数を、同時にコンソール出力できる

Go:複数のコンソール出力
a := 1
b := 2
c := 3
println(a,b,c) // => 1 2 3

PHPでデバッグしようとした場合、「var_dump」を書きまくるのはあるあるかと思いますが、Goだとめっちゃ簡単。
これで、書きまくった後の消し忘れも心配ない…笑

ちなみに、JavaScriptは同じことが可能です。

JS:複数のコンソール出力
var a = 1;
var b = 2;
var c = 3;
console.log(a,b,c); // => 1 2 3

4. 使わない変数があればエラーになる

JavaScriptやPHPでは

JS
var a = 1;
var b = 2;
console.log(a);
PHP
$a = 1;
$b = 2;
var_dump($a);

というコードはなんでもないことですが、

Go
a := 1
b := 2
println(a) // => ./main.go:3:5: b declared and not used

Goだとこのようなエラーが出ます。
「変数b使ってねぇぞ」とのこと。

これは、潜在的なバグを無くすための仕様だそうです。
開発時は、変数の仕様を無視して進めがちなので、注意が必要です。

5. if文の三項演算子や省略形が使えない

残念ながらGoでは、PHPやJavaScriptではよく出てくる、if文の省略形や、三項演算子が使えません。

Go:if文三項演算子
score := 100
score > 80 ? println("合格!") : ""
// => エラー
Go:if文省略形
score := 100
if score > 80 println("合格!")
// => エラー
Go:普通にif文を書く
score := 100
if score > 80 {
    println("合格!")
}
// => 合格!

これも可読性を上げるためみたいですが、…こうなると逆に読みにくいのでは…?なんて思います。笑

6. 「null」ではなく「nil」

…これ、なんか慣れるまで「null」って書いてしまいそうです。笑
「null」ではないので、ご注意を!

7. ポインタの利用

入門したところで、理解が乏しいかと思いますが、Golangは変数のアドレスが確認できるようです。

ちょっと使い所が分かりませんが、おそらく学習を進めていくと、変数のアドレスが必要になることがあるのでしょう…
とりあえず、PHPやJavaScriptにはない概念ですので、サンプルコードだけ載せておききます。

Go:ポインタのサンプル
package main
import "fmt"

func main() {
	a := 5
	var pa *int
	pa = &a
	fmt.Println(pa)  // => 0xc0000140c0
	fmt.Println(*pa) // => 5
}

ちなみに、好奇心で試したらこれでもできました。
普通こんな書き方はしないのかもですが…

Go:ポインタの省略版サンプル
package main
import "fmt"

func main() {
	a := 5
	pa := &a
	fmt.Println(pa)  // => 0xc0000140c0
	fmt.Println(*pa) // => 5
}

8. 関数の返り値には型指定が必須

Go
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つの引数の値を、反対にして返している処理です。

Go:返り値2つreturnできる
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つ以上もいけました。

Go:返り値3つreturnも可能
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の場合、

PHP:配列宣言・代入
$a = [10, 20, 30];

PHPの場合は。宣言らしい宣言不要で、[]とか古い形式だとarray()で囲ってやると、簡単に配列に代入できました。
非常に分かりやすい。
JavaScriptでも、はじめに「let」や「const」、「var」がつくだけで、基本的に同じです。
しかし、Goだと

Go:配列の宣言・代入(省略形)
a := [...]int{10, 20, 30}

となる。なんか、多いですね。
しかし実はこれ、

Go:配列の宣言・代入(ちょっと省略形)
a := [3]int{10, 20, 30}

↑これの省略形で、さらにこれは、

Go:配列の宣言と代入
var a[3]int
a[0] = 10
a[1] = 20
a[2] = 30

↑これの省略形だそうです。
Goでの配列は、原則として、宣言時に配列の個数を指定しておく必要があるということですね。

ちなみに、一度配列の個数が決まったのに、後から強引に入れようとすると…

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では、違うそうです。
たとえば

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言語では配列の一部または全部を切り出した、スライスという参照型のデータをよく使うそうです。

  • 配列をスライスして、使う部分だけ切り出しておく。
  • 切り出した値を使って、処理を行うので、使わない値を持たなくて良い。
    ということです。
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の常識で新しいことを学ぶと面白いですね。
また、間違えているところ等あればご連絡頂けると幸いです。

最後までありがとうございました。

参考

Progate
ドットインストール

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?