はじめに
業務でGo言語を使って製造していくことになり、Go言語を習得していくにあたって、自分の中で理解に苦しんだ箇所や新鮮だった点をまとめてみました。
筆者のレベル
- Java:約3年(設計〜テストまで一通り経験あり)
Java Silver SE17 所持 - Python:実務経験はないが、基礎文法は理解しているレベル
Python3エンジニア認定基礎試験 合格済み - Go:完全未経験で、これから実務で使用予定
文法で驚いた点
① 関数とメソッドの違いが重要
Javaでも区別としてクラスに属する関数はメソッドと呼びますが、
人によっては言い方がバラバラだったりしますが、
ニュアンスで伝わります。
しかし、Goでは「レシーバがあるかどうか」で関数とメソッドが分かれます。
この違いは最初かなり大事なポイントになります。
② 関数・メソッドの書き方に違和感!
func add(a, b int) int {
return a + b
}
上のコードでは、{直前のintは戻り値です。
戻り値の型が後ろにくるのが最初はかなり違和感でした。
さらに、「型 変数」ではなく「変数 型」なのもJavaに慣れていると違和感があります。
また、メソッドはレシーバ、引数、戻り値と要素が多く、()が多すぎて最初はかなり混乱しました。
下のコードで説明します。
type Point struct {
X float64
Y float64
}
func (p *Point) Distance(scale int) float64 {
return math.Sqrt(p.X*p.X + p.Y*p.Y) * float64(scale)
}
最初は「どれが何!?」状態になりました。
分解すると
- (p *Point) → レシーバ(どの型のメソッドか)
- Distance → メソッド名
- (scale int) → 引数
- float64 → 戻り値の型
つまり「Point型に紐づくDistanceメソッドで、intを受け取ってfloat64を返す」
という意味になります。
Javaでいうと下のイメージに近いです。
public double distance(int scale) {
...
}
ただし、Goでは「どの型に紐づくか(レシーバ)」が前に来るのが特徴です。
③ 関数・メソッドは戻り値が複数返せる
func calc(a, b int) (int, int) {
return a * 10, b / 10
}
func main() {
println(calc(100, 200))
}
基本的には戻り値は1つのみというイメージが自分の中では強かったため、
複数の戻り値を返せることは意外でした。
④ ループはforしかない
for i := 0; i < 10; i++ {} // C風
for i < 10 {} // while風
for {} // 無限ループ
Goにはwhileがなく、すべてforで表現します。
Javaではwhile(next())のような処理もよく見ていたため、
最初は違和感がありました。
しかし、ループしたいならforを使えばいいので迷うことがなくて良いと思いました。
⑤ nilって?nullじゃなくて?
var p *int
fmt.Println(p) // nil
Javaでいうnullのような存在です。
PythonではNone、DBではNULLといった表現があるため、
nilという単語は少し新鮮に感じました。
⑥ ポインタや構造体(struct)などCっぽい要素がある
【ポインタ】
x := 10
p := &x
-
x: 値そのもの -
&x: xのアドレス -
p: xを指すポインタ -
*p: xの値
【構造体(struct)】
type User struct {
name string
age int
}
Javaにはポインタの概念がないため、ここはかなり苦戦しました。
構造体もクラスに似ていますが別物で、変にJavaのクラスと比較してしまい、このあたりは理解に時間がかかりました。
⑦ インタフェースはimplementsを書かない
// インタフェース
type Calc interface {
Add(a int) int
}
// 構造体
type User struct {
name string
age int
}
// メソッド(インタフェースを満たす)
func (u User) Add(a int) int {
return u.age + a
}
func main() {
var c Calc = User{name: "太郎", age: 20}
fmt.Printf("来年は%d歳です\n", c.Add(1))
}
Goでは、必要なメソッドを持っていれば、その型はそのインタフェースとして扱うことができます。
Javaのようにimplementsを書く必要がないのはシンプルで良いですが、
分かりにくいと感じる場面もあるのではないかと感じました。
⑧ 例外処理が存在しない
if err != nil {
}
Javaのようなtry-catchは存在せず、エラーは戻り値として扱います。
よって、Goのエラーは「値」であり例外ではないため、上記のようなコードで記述することが一般的です。
⑨ 並行処理に強い
goroutine(ゴルーチン)という記法により、簡単に並行処理が実現できます。
func main() {
add()
go add() //新しいgoroutineを実行
}
上のように、関数の実行時にgoをつけるだけです。
Javaでは並行処理は慎重に扱うイメージでしたが、
Goはgoroutineなどにより並行処理がしやすい言語だと感じました。
まとめ
Goはシンプルですが、Javaとは考え方が大きく異なります。
Java愛が強い自分は「Javaではこうだったのに!!」となりがちなので(笑)、一旦Javaはそばに置いておいたうえでGoと向き合っていきたいと思います。
最初は戸惑うことも多いですが、理解してくるとシンプルさの良さも感じられる言語だと思いました。
まだ今は基礎を習得した段階なので、実務で使用するにあたり気づきなどを今後も記事にしていきたいと思います。
参考文献
・A Tour of Go
・たった1日で基本が身に付く! Go言語 超入門