ざっくりGoの文法まとめ


## 概要

復習も兼ねて、Go言語の文法を簡単にまとめた。

環境設定は以下を参照。
http://qiita.com/chrischris0801/items/ce1d3a493750f67167ec


## 基本

```go:main.go
// コメントは「//」で書く
// Go言語のソースファイルは必ずpackageで始まる
package main

// fmtパッケージをインポートする
import "fmt"

// main関数
func main() {
	fmt.Println("main")
}
```

### package

Go言語のソースファイルはなんらかのpackageに属さなければいけない。
多数のソースファイルのうちの少なくとも1つはmainパッケージに属させないといけない。

### import

外部のソースやパッケージを利用する際には `import` で追加する。

### func

関数の宣言は `func` によって行う。

### ソースコードの実行

コマンドラインで `$ go run filename` と打つと、ソースファイルのコンパイルと実行を同時に行ってくれる。

```bash
$ go run main.go
main
```


## 変数

変数を宣言するときは型宣言もする。

```go
// 方法1; 宣言する段階で値が決まっていない場合
var msg_1 string
msg_1 = "Hello, world"

// 方法2
var msg_2 = "Hello, world" // 初期化に使った型になる

// 方法3; 宣言する段階で値が決まっている場合
msg_3 := "Hello, world" // 宣言と代入を一気に行う
```


## 型

### ゼロ値

変数宣言した時に値を指定しなかった場合、その変数には「ゼロ値」が設定される。

* int: 0
* float64: 0.0
* string: ""
* bool: false
* Array: 各要素がゼロ値の配列
* 構造体: 各フィールドがゼロ値の構造体
* その他の型: nil

### 型変換

型の変換は以下のように行える。

```go
// 変数の宣言
var i int = 1234

// intからstringへの変換
var s string = string(i)
```

### 演算子

演算子は他の言語と同じように、

* 算術演算子: + - * /
* 代入演算子: += -=
* 比較演算子: == != < <= > >=
* 論理演算子: && || !
* インクリメント/デクリメント: ++ --

が使える。


## Array

GoにはArrayとSliceがあり、Arrayは要素数が固定されているがSliceは要素数が固定されていない。

```go
// [要素数]type{中身}
a := [3]int{1, 3, 5}

// 要素数は以下のように省略できる
b := [...]int{1, 3, 5}
```

型はいずれの場合も `[3]int` となる。
Arrayは長さ(length)と要素(element)の型を明らかにしたものであり、例えば`[2]int`と`[3]int`では違う型である。


## Slice

SliceはArrayの要素数の規定が無いもので、長さ(`len`)と最大収容数(`cap`)を持つ。

```go
// 方法1
s1 := []int{1, 3, 5}
len(s1) // 3

// 方法2; makeを使う
// capを省略すると、len == capとなる
s2 := make([]int, 3) // ゼロ値は[0,0,0]

// スライスの末尾に要素を追加
s1 = append(s1, 8, 2, 10)
```


## マップ

keyもvalueも型を指定する。

```go
// 変数の宣言
m := map[string]int{"kurisu":100, "ken":200}

// keyが"kurisu"の要素を削除
delete(m, "kurisu")

// 値を取り出す
// errの値も取り出す
value, err := m["ken"]

fmt.Println(value) // 200
fmt.Println(err) // nil
```


## 制御構文

### if

```go
point := 60;

if score > 80 {
	fmt.Println("Excellent")
} else if score > 60 {
	fmt.Println("Good")
} else {
	fmt.Println("Bad")
}
```

### switch/case

`default` 句でいずれの場合(`case`)にも該当しなかった場合の処理を書きます。

```go:switch.go
signal := "blue"

switch signal {
case "red":
	fmt.Println("Stop")
case "yellow":
	fmt.Println("Caution")
case "green", "blue":
	fmt.Println("Go")
// どのcase節にも一致しなかったときに実行される処理
default:
	fmt.Println("wrong signal")
}
```

```bash
$ go run switch.go
Go
```

### for

単純な繰り返し処理では、for文を使います。
ループの終了には `break` を使い、スキップには `continue` を使う。

```go
for i := 0; i < 10; i++ {
	// break: ループ終了
	if i == 3 { break }

	// fmtパッケージのPrintln関数
	fmt.Println(i)
}
```

### range

Sliceやマップのループ処理には `range` を使う。

```go:slice.go
s := []int{2, 3, 8}

// インデックスと要素を取り出す
for i, v := range s {
	fmt.Println(i, v)
}

// 要素のみを取り出したい場合
for _, v := range s {
	fmt.Println(v)
}
```

マップは以下のようにkeyとvalueを取り出す。

```go:map.go
m := map[string]int{"taguchi":200, "fkoji":300}

// key, value
for k, v := range m {
	fmt.Println(k, v)
}
```


## 構造体とメソッドの定義

以下は四角形の構造体を定義し、面積を算出するメソッドを定義しているコード。

```go:struct.go
package main

import "fmt"

// 構造体の定義
// type name struct { ...フィールド... }
type rect struct {
    width int
    height int
}
 
// メソッド; レシーバ付きの関数
// func (レシーバの変数名 レシーバの型) メソッド名(パラメータリスト) 戻り値の型 {
//   # 処理
//   return 戻り値
// }
func (r *rect) area() int {
	return r.width * r.height
}

// mainで実行する
func main() {
	// 構造体の初期化
	r := rect{width: 10, height: 5}
	fmt.Println("area: ", r.area())
}
```

```bash
$ go run struct.go
50
```

### ポインタ

ポインタとは「あるメモリ領域を指し示すデータ」である。
変数を宣言すると、特定のメモリ領域に保存され、ポインタはその値を示すことになる。
ポインタを使うときは `*` と記述する。

レシーバの値を更新するようなメソッドでは、レシーバはポインタにしなければいけない。
レシーバにポインタを使うと、変数（構造体）のフィールドの値を変更することができるが、使わないと変更はもとの変数に反映されない。

```go
// int型から新たにmyType型の構造体を宣言
type myType int

// レシーバが値（非ポインタ）のメソッド
func (value myType) setByValue(newValue myType) {
	value = newValue
}

// レシーバがポインタのメソッド
func (value *myType) setByPointer(newValue myType) {
	*value = newValue
}

func main() {
	var x myType = 0
	
	x.setByValue(1)
	fmt.Println(x) // xは0のまま
	
	x.setByPointer(1)
	fmt.Println(x) // xが1になる
}
```


## コンポジション

構造体の中に構造体を埋め込むことができる。

```go
package main

import "fmt"

type Person struct {
   Name string
   Address Address
}
 
type Address struct {
   Number string
   Street string
   City   string
   State  string
   Zip    string
}
 
func (p *Person) Talk() {
    fmt.Println("Hi, my name is", p.Name)
}
 
func (p *Person) Location() {
    fmt.Println("I’m at", p.Address.Number, p.Address.Street, p.Address.City, p.Address.State, p.Address.Zip)
}

func main() {
p := Person{
		Name: "Steve",
		Address: Address{
			Number: "13",
			Street: "Main",
			City:   "Gotham",
			State:  "NY",
			Zip:    "01313",
		},
	}

    p.Talk()
    p.Location()
}
```


## インターフェース

PersonもCitizenも、Humanの一部であるので、Humanインターフェースを持つようにする。

```go
type Human interface {
	Talk()
}
 
func SpeakTo(h Human) {
	h.Talk()
}
 
func main() {
	p := Person{Name: "Dave"}
	c := Citizen{Person: Person{Name: "Steve"}, Country: "America"}

	SpeakTo(&p)
	SpeakTo(&c)
}
```


## Goroutineとchannel

goroutineは並行処理ができる機能で、channelは並行処理中に結果の受け渡しを行うための機能。

```go:goroutine.go
package main

import (
	"fmt"
	"time"
)
 
func task1(result chan string) {
	time.Sleep(time.Second * 2)
	// channelに結果を出力する
	result<- "task1 result"
}

func task2() {
	fmt.Println("task2 finished")
}
 
func main() {
    // channel型のインスタンス
	result := make(chan string)

    // goroutineとして実行できる
	go task1(result)
	go task2()

    // task1の結果を取得する
    // 結果を取得できるまで待機している
	fmt.Println(<-result)

	time.Sleep(time.Second * 3)
}
```

```bash
$ go run goroutine.go
task2 finished
task1 result
```