Goを真面目に勉強する〜2.基本構文〜

# はじめに
Goをはじめて１年半。アウトプットが進まない私が、専門家の@tenntennさんから受けたマンツーマンレッスンの内容をまとめて、Goのスキルアップを目指します。Goの基礎から丁寧に学んでいきます。
記事のまとめは以下の通りで順次作成していきます。
今回は「2.基本構文」になります。

## シリーズの一覧
1. [Goについて知っておく事](https://qiita.com/bluemon0919/items/dabda22b50df44999790)
2. 基本構文（今回）
3. [関数と型](https://qiita.com/bluemon0919/items/000de655f4ab27ea43ae)
4. [パッケージとスコープ](https://qiita.com/bluemon0919/items/4127ecbcadadd9be2b1c)

## 本記事の内容
今回学ぶ内容は以下の通りです。

- 変数
- 定数
- 制御構文
 - 条件分岐
 - 繰り返し

# 組み込み型
定数、変数を取り扱うにあたって、ここで紹介しておきます。Goでは以下の型が組み込み型として用意されています。組み込み型の種類と同時に、Goでは重要になってくるゼロ値も記載しました。
ユーザ定義型については今回の記事では説明しません。


|型名|説明|ゼロ値|
|:-------------------|:-------------------|:-------------------|
|int, int8, int16, int32, int64|符号付き整数型. intは32または64bit|0|
|uint, uint8, uint16, uint32, uint64|符号なし整数型. uintは32または64bit|0|
|float32, float64|浮動小数点数|0|
|uintptr|ポインタ値を格納するのに十分な大きさの符号なし整数型|0|
|byte|uint8のエイリアス|0|
|rune|int32のエイリアス|0|
|string|文字列|""|
|bool|真偽値|false|
|error|エラー|nil|
参考：[https://golang.org/ref/spec#Types](https://golang.org/ref/spec#Types)

#変数宣言
参考:[https://golang.org/ref/spec#Variable_declarations](https://golang.org/ref/spec#Variable_declarations)
###型指定による変数宣言
Goは静的型付け言語なので、変数には型が存在します。変数宣言の基本構文は`var 識別子 型`ですが、その他にも色々な書き方ができます。
C言語のように変数を初期化する必要はなく、宣言時にゼロ値に初期化されます。（各組み込み型のゼロ値は、組み込み型の一覧を参照）

```go

var n int // 変数nをint型で宣言する（ゼロ値で初期化される）
var a, b, c int // 変数a,b,cをint型で宣言する（ゼロ値で初期化される）
```

```go

var n int = 100 // 変数nをint型で宣言し、100を代入する
var a, b, c int = 1,2,3 // 変数a,b,cをint型で宣言し、a=1,b=2,c=3を代入する
```


###型推論による変数宣言
変数を宣言する際に型を省略して書くこともできます。この場合、型無しの変数が作られるのではなく、型推論によってデフォルトの型で変数が作られます。

```go

// 右辺100が整数のため、型推論により変数nをint型で宣言し、100を代入する
var n = 100

// 変数aをint型で宣言し、1を代入する
// 変数bをfloat64で宣言し、3.4を代入する
var a, b = 1, 3.4
```

さらにvarを省略して書くこともできます。ただし、この書き方は関数内でしか使えません。

```go

// varは省略可能。ただし関数内しか使えない。
// 右辺100が整数のため、型推論により変数nをint型で宣言し、100を代入する
n := 100

// 変数aをint型で宣言し、1を代入する
// 変数bをfloat64で宣言し、3.4を代入する
a, b := 1, 3.4
```

まとめて書くこともできます。この書き方をグループ化と言います。

```go

// まとめて書くこともできる
var (
    n = 100
    a, b, c = 1, 2, 3
)
```
**型推論によるデフォルトの型**

|種類|デフォルトの型|
|:-------------------|:-------------------|
|整数|int|
|浮動小数点数|float64|
|ルーン|rune|
|文字列|string|
|真偽値|bool|

ちなみに、Goは未使用の変数を許さないため、未使用変数があるとビルドエラーになります。
[The Go Playground](https://play.golang.org/p/14SrCz7e1K4)
`./main.go:4:6: n declared and not used
Go build failed.`

#定数宣言
定数はコンパイル時から値が変わらないものです。名前無しの定数と名前付きの定数、定数式があります。
###名前無し定数
名前無し定数には以下のような種類があります。数値リテラルには2進数,8進数,16進数も用意されています。
参考：[https://golang.org/ref/spec#Integer_literals](https://golang.org/ref/spec#Integer_literals)

|種類|例|
|:-------------------|:-------------------|
|数値リテラル|100（整数)<br>1.5(浮動小数点数)<br>0b01（2進数）<br>0o72（8進数）<br>0xe1（16進数）|
|文字列リテラル|"hoge"|
|ルーンリテラル|'A'|
|真偽値リテラル|true, false|

ちなみに、数値リテラルを桁ごとにまとめて表現する方法も用意されていて、とても便利です。

```

0b0100_1000_0000_0101 // 0b0100100000000101と同じ
0x_67_7a_2f_cc_40_c6  // 0x677a2fcc40c6と同じ
```

###名前付き定数
名前付きの定数宣言の基本構文は`const 識別子 型 = 式`ですが、その他にも色々な書き方ができます。
参考：[https://golang.org/ref/spec#Constant_declarations](https://golang.org/ref/spec#Constant_declarations)

```go

// 定数nをint型、数値100で宣言する
const n int = 100
```

```go

// 定数nを型無し、数値100で宣言する
// 定数の場合は型無しが存在する
const n = 100
```

```go

// まとめて書くこともできる
const (
    n = 100
    m = 200
)
```

###定数式
100+200のように定数から成る演算式を定数式と言います。定数式はコンパイル時に演算が行われます。

|種類|例|演算結果|
|:-------------------|:-------------------|:-------------------|
|四則演算|100 + 200|300|
|シフト演算|1 << 2|4|
|文字列結合|"hello," + "world!"|"hello,world!"|
|関係演算、論理演算|10 == 20|false|

名前付き定数の宣言時に定数式を用いることもできます。

```go

// 定数nを型無し、数値300で宣言する
// 定数nを定数式で宣言する
const n = 100 + 200
```

###変数に定数を代入する
定数には型無しが存在しますが、変数には型が存在するため、定数を変数に代入する際に型推論が働きます。

```go

const n = 100 // 定数nを型無し、数値100で宣言する
var a = n // 型推論により変数aをint型で宣言し、100を代入する
```

###名前付き定数の右辺は省略できる
グループ化された定数宣言の中では、２つ目以降の名前付き定数宣言の右辺を省略することができます。この場合、右辺は１つめの定数宣言の右辺と同じになります。

```go

const (
    a = 1
    b // b=1
    c // c=1
)
```

`iota`を利用すると連続した定数を宣言することができます。`iota`はグループ化された定数宣言の中で利用される仕組みで、0から始まり１つずつ加算される値として扱われます。
参考：[https://golang.org/ref/spec#Iota](https://golang.org/ref/spec#Iota)

```go

const (
    a = iota // iotaの初期値は0
    b // b=1
    c // c=2
)
```

グループ化された定数宣言の２つ目以降が１つめの右辺が同じになる特徴と、`iota`を組み合わせると、色々な定数宣言ができるようになります。

```go

const (
    a = 1 << iota // iotaの初期値は0
    b // b=2
    c // c=4
)
```

```go

const (
    a = 1 << iota // iotaの初期値は0
    b = 1 << iota // b=2(iota=1)
    c = 3 // c=3
    d = 1 << iota // d=8(iota=3)
)
```

#制御構文
##条件分岐 if文
```go

if n == 0 {
    // 変数nが0と等価なら実行される
}

if n == 0 {
    // 変数nが0と等価なら実行される
} else {
    // 変数nが0と等価以外なら実行される
}

if n == 0 {
    // 変数nが0と等価なら実行される
} else if n > 0 {
    // 変数nが0より大きければ実行される
} else {
    // それ以外なら実行される
}
```

if文の場合、条件式の前にステートメントを書くことができる。
`if ステートメント; 条件式 {`

```go

if a := f(); a == 0 {
    // 関数fの返り値を変数aに代入し、aが0と等価なら実行される
} else {
    // 変数aが0と等価以外なら実行される
}
```

###if文の変数スコープについて
if文のステートメントの中で宣言した変数のスコープは、ifとelseのブロック内になります。ブロックは"{"から"}"までの間のことです。

```go

if a := f(); a == 0 {
    // ifのブロック
} else {
    // elseのブロック
}
```

`else if`の場合、`else`の次の`if`は次のifブロックになります。次のifブロックもelseブロックに含まれますので、最初のif文のステートメントで宣言した変数のスコープ

```go

if a := f(); a == 0 {
    // ifのブロック、aはスコープ内
} else if b := f(); a > 0 && b > 0 {
    c := b
    // ifのブロック
    // a、b、cはスコープ内
} else {
    d := b
    // elseのブロック
    // a、b、dはスコープ内
    // cはスコープ外
}
// a、b、c、dはスコープ外
```

##条件分岐 switch文
Goではswitch文のcase句でbreakを書く必要がありません。また、case句で式が利用できることが特徴です。式が使えるため、if文を並べて書くよりはswitch文を利用した方がスッキリまとめることができます。

```go

switch {
case n == 0: // 式が使える
    // 変数nが0の場合に実行される
    // breakは不要
case n > 0, n < 10: // ２つ以上の条件を書ける
    // 変数nが０より大きい場合に実行される
default: // defaultは書かなくてもいい
    // それ以外の場合に実行される
}
```

caseを跨いで処理をしたい場合は`fallthrough`を使います。

```go

switch n {
case 0:
    // 変数nが0の場合に実行される
    fallthrough
case 1, 2:
    // 変数nが0、1、2の場合に実行される
}
```

#繰り返し for文
Goの繰り返し構文はforしかない（while文は無い）
for文は大きくfor句、単一条件、range句の３つに分類できる。

```go

// for句の利用
// 初期値; 継続条件; 更新文
for i := 0; i < 10; i++ {
}
```

```go

// 単一条件の利用
// 継続条件
for i < 10 {
}
```

```go

// range句の利用
// rangeを使ったループ
for i, v = range n {
}
```

for句や単一条件の利用によるfor文は、初期値、継続条件、更新文を省略することができます。例えば、単一条件の利用で継続条件を省略すると、以下のように無限ループが作れます。

```go

// 何も書かない場合は無限ループ
for {
    break // breakで抜け出せる
}
```
##最後に
今回記事を書くにあたってGoの言語仕様を確認しながら進めることで、より理解も深まったと思います。次回は型と関数についてまとめようと思います。