Go 基本的な文法のアウトプット(変数、関数、For・Switch文、Defer)

# 初めに
[Goの公式チュートリアル](https://go-tour-jp.appspot.com/welcome/1)を使用して勉強した内容をアウトプットするため記事を投稿する。

## パッケージ

### 記述の初め方

Goでは、mainパッケージから開始する。
```go
package main
```

### パッケージのインポート

##### 記述方法１
```go
import{
 "パッケージ１"
 "パッケージ２"
}
```
##### 記述方法2
```go
import "パッケージ1"
import "パッケージ2"
```
記述方法1のほうがコンパクトで分かりやすい。

### エクスポート
最初の文字が大文字だと、エクスポートされて外部パッケージからアクセスすることができる。
小文字だと、外部パッケージからアクセスすることができない。

##### 基本的な書き方
mainパッケージを導入し、main関数内に処理を記載する。
```go
package main

func main() {

}
```


## 関数

##### 基本的な書き方

```go
func add(a int, b int) int {
 return a + b
}

//関数呼び出し
func main() {
    sum := add(3, 4)
    fmt.Println(sum) // 結果: 7
}
```

##### 複数の戻り値
```go
func numbers() (int, int) {
 return 5, 7
}
```

##### 引数の型が同じ場合
```go
func 関数名(引数, 引数 型) {
 処理
}

// 例：int型の引数2つと、string型の引数1つの場合
func 関数名(引数, 引数 int, 引数 string) {
 処理
}
```

##### 戻り値に名前をつける(naked return)
定義した変数と、関数の戻り値の変数名が異なっていたり、returnがなければエラーになる。
また、関数のブロック内の変数でvarや := を使用して定義してもエラーになる。
```go
func 関数名()(変数名1, 変数名2) {
 変数名1 = "test1"
 変数名2 = "test2"
 return
}
```

### 関数は値である
Goの関数は値であるため、変数に格納することができる。
また、関数の引数に関数を用いることもできる。

##### 例
###### 関数を変数に代入
```go
var hoge = func(){}
// 呼び出し
hoge()
```

###### 関数を関数の引数に用いる
```go
呼び出す関数名(引数の関数名)
```

```go
var Puls = func(a, b int) int {
	c := a + b
	return c
}

func Puls2(fn func(int, int) int) int {
	ret := fn(2, 2)
	return ret
}

func main() {
	ret := Puls(1, 1)
	fmt.Println(ret)
	ret = Puls2(Puls)
	fmt.Println(ret)
}
```
###### 出力結果
```terminal
2
4
```

### 関数を戻り値にする
関数を戻り値にすることも可能である。

```go
func 関数名() func() 戻り値である関数の戻り値の型{}
```

```go
func Test() func() int {

	return func() int {
		return 1
	}
}

func main() {
    // retにTest関数が格納される
	ret := Test()
    // Test関数の中の戻り値の関数を呼び出す
	fmt.Println(ret())
}
```
###### 出力結果
```terminal
1
```
### Closure
Closure関数に定義している変数`a`の範囲は、`increment1`と`increment2`で異なることがわかる。

```go
func Closure() func() int {
	var a int
	return func() int {
		a++
		fmt.Println(a)
		return a
	}
}

func main() {
	increment1 := Closure()
	increment2 := Closure()
	increment1()
	increment1()
	increment2()
	increment2()
}
```
Closure関数に定義している変数`a`の範囲は、`increment1`と`increment2`で異なることがわかる。
###### 出力結果
```terminal]
1
2
1
2
```

また、Closure関数で定義した変数をmain関数ないで使用するとエラーになる。

```go
func Closure() func() int {
	var a int
	return func() int {
		a++
		fmt.Println(a)
		return a
	}
}

func main() {
	increment1 := Closure()
	increment1()
	fmt.Println(a)
}
```

###### 出力結果
```terminal
undefined: a
```

上記からわかるように、クロージャーは変数のスコープを限定することができる。

## 変数
### varを用いた宣言
型はなくとも宣言は可能で、Println関数で型を付与せずに宣言をした変数を出力するとfalseが出力される。

```go 
var test
```
初期値を与えずに変数を宣言し、型を付与するとゼロ値が与えられる。
bool型はfalse、int型は0、string型は""がゼロ値。

```go
var b bool
var i int
var s string
fmt.Println(b, i, s)

// 出力結果
false 0 
```
初期化子も同時に付与でき、その場合、変数の型は初期化子の型になる。
型を付与せずに代入した場合は、型推論が行われる。
```go
// 型あり
var i, j int = 1, 2
// 型省略(型推論)
var b, f, s = true, false, "st"
// 初期化子と別の型の値を代入してみる
var b = "error"

// エラー内容　
./prog.go:9:6: b redeclared in this block
	./prog.go:8:6: other declaration of b
```

##### 再代入
型が同じであれば再代入が可能。

```go
var x, y int = 3, 4
var s, t = "s", "t"
x, y = 5, 5
s, t = "a", "i"
```
### :=を使用した宣言
関数の中のみで:=を使用して代入できる。
型は初期化子の型となり、自分で記載することはできないようだが、変数の代入を行う場合は、シンプルなGoとの相性もありこちらを使用した方が見やすいように思う。
関数の外で使用すると構文エラーになる。

```go
func main() {
	i := 1
	s, b := "st", true
}
```

##### 再代入
varで宣言した変数同様に型が同じであれば再代入可能。

```go
func main() {
	i := 1
	s, b := "st", true
	i = 2
	s, b = "rest", false
	fmt.Println(i, s, b)
}

// 出力結果
2 rest false
```

## 型
型の一覧は以下を参照。
https://go-tour-jp.appspot.com/basics/11

## For文
#### 基本形
・中括弧が不要。
・波括弧が必須。
・「初期化ステートメント」「後処理ステートメント」は必須ではない。
```go
// 基本形
// []は分かりやすく書いているだけなので実際のコードには不要
for [初期化ステートメント]; [条件式]; [後処理ステートメント] {}

// 「初期化ステートメント」「後処理ステートメント」を使用しない場合
// セミコロンは省略可能
for ; [条件式]; {}

```

#### 無限ループ
```go
for{}
```

## if文
#### 基本形
・中括弧が不要。
・波括弧が必須。

```go
if [条件式] {}
```

#### short statement
・条件式の前に評価するための式を記載する。
・short statementの変数はif文のスコープ(else ブロック内含む)内のみで使用可能である。
・この機能があることにより、if文でのみ使用する変数のスコープを、if文のブロック内に設定することができる。

```go
if [short statement] ; [条件式] {}
```

例
```go
func main() {
  if i := 1; i == 1 {
    fmt.Println("Go")
  }
}

// 出力結果
Go
```

### 指定した時間ループする

指定した時間ループするコードを書く機会があったので備忘録として記載する。

```go
now := time.Now()
// 16の箇所はループさせたい秒数を記載する
for (16 * time.Second) > time.Since(now) {}
```


## Switch文
#### 基本形
Goのswitch文は、caseの条件が当てはまれば自動的にbreakステートメントが付与される。
また、caseは定数である必要がない。
caseの条件が全て満たされなかったらdefaultが処理される。
defaultは省略可。
また、caseの値は複数指定できる。

```go
switch (条件){
	case 値:
		処理
	case 値, 値:
		処理
	default:
		処理
}
```

例

```go
// caseの条件が満たされると、次のcaseが評価されずにbreakが実行されていることがわかる
func main() {
	i := 1
	switch i{
		case 1:
			fmt.Println("1つめ")
			i++
			fmt.Println(i)
		case 2:
			fmt.Println("2つめ")
		default:
			fmt.Println("3つめ")
	}
}

// 出力結果
1つめ
2
```

#### fallthrough
fallthroughを使用すると次のcase文の処理が実行される。
fallthroughを実行した次のcaseの評価が満たされていなくとも実行がされるようである。

例
```go
func main() {
	i := 1
	switch i {
		case 1:
			fmt.Println("1つめ")
			fallthrough
		case 2:
			fmt.Println("2つめ")
			fallthrough
		default:
			fmt.Println("3つめ")
	}
}

// 出力結果
1つめ
2つめ
3つめ
```

#### boolean

switchの後に何も記載がない場合はcaseの評価がtrueの場合に処理が実行される。
また、switchの後にfalseを付与するとcaseの評価がfalseの場合に処理が実行される。
場合によってはif文よりもシンプルに条件分岐が可能である。

```go
// caseの評価がtrueの場合に処理を実行
func main() {
	i := 1
	switch {
		case 1 == i:
			fmt.Println("1つめ")
		case 2 == i:
			fmt.Println("2つめ")
		default:
			fmt.Println("3つめ")
	}
}

// 出力結果
1つめ

// caseの評価がfalseの場合に処理を実行
func main() {
	i := 1
	switch false{
		case 1 == i:
			fmt.Println("1つめ")
		case 2 == i:
			fmt.Println("2つめ")
		default:
			fmt.Println("3つめ")
	}
}

// 出力結果
2つめ
```

## Defer
#### 基本形
deferに渡した関数は、呼び出し元の関数の処理が終了してから実行される。
渡した関数の引数はすぐに評価される。

```go
func main() {
	defer fmt.Println("2つ目")

	fmt.Println("1つ目")
}

// 出力結果
1つ目
2つ目
```

#### 複数deferの使用
まだ勉強中であるが、以下のページを参照すると分かりやすい。
[A Tour of Go Stacking defers](https://go-tour-jp.appspot.com/flowcontrol/13)