CrescPia

初めての Go 言語

Go 言語始めました。
「他言語プログラマーのためのイディオマティック Go 実践ガイド」という副タイトルの本を読んでいます。

対象読者は『2 番目(あるいは 5 番目あたりかもしれませんが)にマスターするプログラミング言語を選ぼうとしているソフトウェア開発者』とのことです。
随所に他言語と比較した説明があります。
関数の引数は構造体であっても「値渡し」であるところの説明では、『Java, JavaScript, Python, Ruby といった言語でプログラミングした経験があれば、この構造体の振る舞いはとても変わっていると思うことでしょう。』といった感じで他言語プログラマーの目線で説明してくれます。

Go 言語はじめました

Go 言語が出た当初に Hello World! だけやった記憶があります。
バージョン 1.0 が 2012 年にリリースされたとのことですので、12 年ぶり 2 度目のチャレンジです。
Go の並列処理を触ってみたいと思っていました。
そう思っていつの間にか 12 年が過ぎていました・・・。
初めてのGo言語 : 他言語プログラマーのためのイディオマティックGo実践ガイド

メソッド

並列処理はまたいずれ試すとして、Go 言語を学び始めて面白いと思った点についてちょっと書いてみます。
「メソッド」についてです。

クラスがない

オブジェクト指向を実現するのにクラスという概念は切っても切れないものと思っていました。
これから登場する言語には当然、クラスは含まれているものと思っていましたが、Go 言語にはありません。
でもクラスとは別の方法で、オブジェクト指向は実現できています。

// 構造体 User を定義
type User struct {
	Name string
	Age  int
}

// 構造体 User に紐づくメソッドを定義
func (u *User) Greet() {
	fmt.Printf("Hello, I am %s (%d)\n", u.Name, u.Age)
}

データは構造体で表します。(type User struct ・・・)
操作するメソッドは、別で定義して対象の構造体と紐づけています。(func (u *User) Greet() ・・・
func と関数名 Greet の間の (u *User) が対象の構造体で「レシーバ」と呼ばれます。
以下のように実行できます。

func main() {
	u := User{Name: "Taro", Age: 30}
	u.Greet()
	// Hello, I am Taro (30)
}

レシーバは任意の型が OK

上記は構造体に対してメソッドを紐づけましたが、int 型でも OK です。
ただし、型が同じパッケージ内で宣言されている必要があるので、int を基底型とした myint 型を宣言して試してみます。

type myint int

func (i myint) DispNumber() {
	fmt.Printf("Value is %d\n", i)
}

func main() {
	var num myint = 10;
	num.DispNumber()
	// Value is 10
}

レシーバは関数型でも OK

レシーバが関数型でも OK です。
関数に関数を紐づけることもできてしまいます。
今のところ使う場面を想像できませんが、こういったことにも慣れていきたいと思います。

type strFuncType func() string

func Greet() string {
	return "Hello World!\n"
}

func (f strFuncType) repeatGreeting(num int) string {
	var result string
	for i := 0; i < num; i++ {
		result += f()
	}
	return result
}

func main() {
	var f strFuncType = Greet
	fmt.Println(f.repeatGreeting(3))
	// Hello World!
	// Hello World!
	// Hello World!
}