🐭

goの基本文法 No.5

2020/09/30に公開

2020-09-29執筆
A Tour of Goに沿ってGoの文法をまとめます。
これまでにJavaScriptやPythonなどのリッチ言語しか使ったことがなかった自分のためにまとめたものです。
なのでこれまでに上のようなリッチ言語を触ったことがあり、これからGoを触ってみようと考えている人の参考になればと思います。
文章の構成は、基本的に

  1. 概要
  2. コード
  3. コードの説明

の構成にしているつもりです。概要で簡単な説明をし、コードで例を示して、さらにコードの説明で細かい説明をするといった構成です。

Map

Map

配列はキーが自動的に0から割り振られていました。自分でキーを割り振りたい時に使うのがマップです。マップはmake関数で作成します。

変数名 := make(map[キーの型])

配列と似ていますが、キーの型を宣言します。具体的な例でみてみましょう。

// code:5-1
type Vertex struct {
	x, y float32
}

func main() {
	point := make(map[string]Vertex) // ①
	point["A"] = Vertex{ // ②
		1, 2,
	}

	fmt.Println(point["A"]) // ③
}
/*実行結果
{1 2}
*/
  1. キーが文字列型で要素がVertex型のマップの変数pointを宣言しています。
  2. Aというキーに{1, 2}という要素を代入しています。
  3. 要素の一つにアクセスする時は変数名[キー名]という形で指定します。

Mapリテラル

ここでは代入する値(リテラル)の例を提示します。

// code:5-2
type Vertex struct {
	Lat, Long float64
}
// 一般
var m = map[string]Vertex{
	"Bell Labs": Vertex{
		40.68433, -74.39967,
	},
	"Google": Vertex{
		37.42202, -122.08408,
	},
}
// 短縮
var m = map[string]Vertex{
	"Bell Labs": {40.68433, -74.39967},
	"Google":    {37.42202, -122.08408},
}

func main() {
	fmt.Println(m)
}
/*実行結果
map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]
*/

このように:を挟んで右側に値、左側にキーという書き方も出来ます。

マップの変更

値の変更は簡単です。

// code:5-3
func main() {
	m := make(map[string]int)

	m["Answer"] = 42
	fmt.Println("The value:", m["Answer"])

	m["Answer"] = 48 // ①
	fmt.Println("The value:", m["Answer"])

	delete(m, "Answer") // ②
	fmt.Println("The value:", m["Answer"])

	m["Question"] = 77

	// ④
	v, ok := m["Answer"]
	fmt.Println("The value:", v, "Present?", ok)
	w, no := m["Question"]
	fmt.Println("The value:", w, "Present?", no)
}
/*実行結果
The value: 42
The value: 48
The value: 0
The value: 0 Present? false
The value: 77 Present? true
*/
  1. 値の変更は再代入するだけです。
  2. 削除はdelete関数でできます。
  3. マップを代入するとその要素の値vとその要素が存在するかの真偽値okを取り出すことができます。存在する時はtrue、存在しなければfalseが代入されます。値が存在しない時は要素の値はゼロ値になります。

関数は値

goの基本文法No.1で紹介したのでここでは割愛します。

クロージャー関数

関数閉包ともいいます。クロージャとは、本体の外部から変数を参照する関数値のことです。関数は、参照された変数にアクセスしたり、代入したりすることができます。具体例を見てみましょう。

// code:5-4
func adder() func() int {
	sum := 0
	return func() int {
		sum++
		return sum
	}
}

func main() {
	f := adder()
	fmt.Printf("type of f:%T \n", f)
	fmt.Println(f())
	fmt.Println(f())
	fmt.Println(f())
}
/*実行結果
type of f:func() int 
1
2
3
*/

adder関数は関数を返します。main関数では変数fにadder関数が返す関数func() intが代入されます。このfunc() intは変数sumを参照しています。main関数で変数fが呼び出される度にfunc() intが実行され、sum++でインクリメントされるので実行の度に値が増えていきます。

Exercise: Fibonacci closure

最後に該当するエクササイズの概要と私の解答を載せておきます。参考までに。
私の解答

Discussion