Go言語の基礎 S2

# Go言語の文法

## 変数

### 型の種類
|型の名前|説明|サイズ|範囲|
|-|-|:-:|:-:|
|bool(boolen)|論理値型|1byte|``true``/``false``|
|string|文字列型|-|-|
|float32|単精度浮動小数点数|4byte|有効桁数6桁の実数|
|float64|倍精度浮動小数点数|8byte|有効桁数14桁の実数|
|int32|符号付き整数|4byte|-2147483648 ~ 2147483647|
|int64|符号付き整数|8byte|-9223372036854775808 ~ 9223372036854775807|
|int|符号付き整数|4byte / 8byte|``int32``または``int64``と同じ|
|rune|int32のエイリアス|4byte|Unicodeのコードポイント1文字分を格納|
|complex64|複素数|8byte|``float32``の実数部と虚数部を持つ複素数|
|complex128|複素数|16byte|``float64``の実数部と虚数部を持つ複素数|

### var(変数)

```go
var name string
```
``var 変数名 型``で変数を**宣言**できる。

```go
var name string
name = "田中"
```

``変数 = 値``で変数に値を**代入**できる。

```go
var name string = "田中"
var name = "田中" // "田中"というのをみて型を推論してくれる
```

宣言と代入を同時に行うことができる。宣言と代入を同時に行うことを**初期化**という。

```go
func main() {
    name := "田中"
}
```

var の短縮形として``:=``がある。ただし関数内でしか使えないことに注意。

```go
package main

func main() {
    var flag bool = true
    // var flag = false このように書くことも可能

    var name = "田中"
    
    var number = 10

    // 以下のように連続して宣言することも可能
    var (
        status = true
        lang = "jp"
    )
}
```

### const(定数)

```go
const gravity string
```

基本的な宣言や代入の仕方については変数と同様だが、宣言できる型が、文字列(String)、数値(Integer)、浮動小数点数(Floating)、真偽値(Boolen)、ルーン値(Rune)、複素数(Complex)だけとなっている。その他独自の型を定数にすることはできない。
varと違う点は再代入できないということ。だから**不変**であるものに限り使うべきだろう。

### スコープについて
関数の外でも変数の宣言は行うことができ、変数に限らず関数などで**最初の名前の文字を大文字**にすることで他のパッケージからアクセスできるようになる。

## 演算子

### 算術演算子

| 演算子 | 説明|  例   |
|-----------|-------------|--------------------------------------|
| +          | 和          |``3+7``, ``4+6``, ``"Hello"+"World"``|
| -          | 差          |``14-4``, ``13-8``                   |
| *          | 積          |``3*7``, ``4*6``                     |
| /          | 商          |``10/2``, ``7/3``                    |
| %          | 余り        |``8%3``, ``6%4``                     |

```go
package main

func main() {
    println(3 + 7) // 10

    a := 3
    b := 7
    println(a + b) // 10
    
    println(14 - 4) // 10
    c := 14
    d := 4
    println(c - d) // 10
    
    println(3 * 7) // 21
    println(10 / 2) // 5
    println(8 % 3) // 2
}
```


### 代入演算子

|演算子|説明|例|
|--|-----------------------------|----------|
|++| 変数に1加える, インクリメント|``i++``[^1]|
|--| 変数に-1加える, デクリメント |``i--``    |
|+=| 右にある値を左の値に加える   |``i += 1`` |
|-=| 右にある値を左の値から減らす |``i -= 1`` |

[^1]: ``i``は変数で型はintとする

```go
package main

func main() {
    a := 0
    println(a) // 0

    a++
    println(a) // 1

    a--
    println(a) // 0

    a += 3
    println(a) // 3

    a -= 2
    println(a) // 1
}
```

### 比較演算子
|演算子|説明|例|
|---|------------|-----------|
|==|等しい       |``i == 1`` |
|!=|等しくない   |``i != 1`` |
|< |小なり       |``i < 0``  |
|<=|小なりイコール|``i <= 0`` |
|> |大なり       |``i > 0``   |
|>=|大なりイコール|`` i >= 0``|


```go
package main

func main() {
    a := 1
    println(a == 1) // true
    println(a != 1) // false

    b := 0
    println(b < 0) // false
    println(b <= 0) // true
}
```

### 論理演算子

|演算子|説明|例|
|----|-----------|-|
|&&  |または, and|``i <= -5 && i < 0 &&``|
|\|\||かつ, or   |``i <= -5 \|\| i > 10``|
|!   |でない, not|``!flag``[^2]          |

[^2]: ``flag``は変数で型はboolen(bool)とする

```go
package main

func main() {
    a := 3
    println(a > 0 && a < 5) // true
    println(a < 0 && a < 5) // false
    
    println(a < 0 || a < 5) // true

    println(!(a < 0 || a < 5)) // false
}
```

### アドレス演算子

| 演算子 | 説明 |
|:-:|:-:|
| &  | アドレスを取得  |
| *  | アドレスが指す値を取得  |


```go
package main

func main() {
    var a int
    println(&a) // 0xc000046738 <- この値は環境によって変わる

    b := &a
    a = 5

    println(*b) // 5
}
```

## if(条件分岐)

```go
package main

func main() {
    var age int = 17

    if age >= 15 {
        println("15歳以上です") // 15歳以上です
    }
}
```

``if 条件 {なんらかの処理}`` と書くことができる。条件のところは丸括弧で囲む必要はない。

### if-else

```go
package main

func main() {
    var age int = 17

    if age < 15 {
        println("15歳未満です")
        
    } else {
        println("15歳以上です") // 15歳以上です
    }
}
```

``if 条件 {なんらかの処理} else {なんらかの処理}`` と書くことができ、``else``はその条件に当てはまらなかった場合、実行される。

```go
package main

func hello() string {
    return "Hello"
}

func main() {
    /*
    chars := hello()
    if chars == "Hello" {
        println("Hello") // Hello
        
    } else {
        println("No Hello")
    }
    */
    
    if chars := hello(); chars == "Hello" {
        println("Hello") // Hello
        
    } else {
        println("No Hello")
    }
}
```

上記のように一行で書いてしまうことも可能。ただし``chars``はifの中でしかアクセスできない。変数を宣言するところと条件のところをセミコロン(;)で区切る。

### if-else if-else

```go
package main

func main() {
    var point int = 75

    if point >= 80 {
        println("80点以上")
        
    } else if point < 60 {
        println("60点未満")
        
    } else {
        println("80点未満、60点以上") // 80点未満、60点以上
    }
}
```

elseの後にifを続けることが可能。

## switch(条件分岐)
``switch``は``if``と同じようなことはできるが、``switch``は、分岐の数が多く、それぞれの分岐毎の処理が少ないときに用いられる。

```go
package main

func main() {
    var age int = 21
    
    switch age {
    case age >= 20:
        println("20歳以上") // 20歳以上

    case age >= 18:
        println("18歳以上")

    case age == 0:
        println("0歳")
    }
}
```

``switch 変数 {case...}`` と書くことができる。

```go
package main

func main() {
    switch age := 21; {
    case age >= 20:
        println("20歳以上") // 20歳以上

    case age >= 18:
        println("18歳以上")

    case age == 0:
        println("0歳")
    }
}
```

上記のように一行で書いてしまうことも可能。ただし``age``は``switch``の中でしかアクセスできない。変数を宣言するところと条件のところをセミコロン(;)で区切る。

### default

```go
package main

func main() {
    switch age := 15; {
    case age >= 20:
        println("20歳以上")

    case age >= 18:
        println("18歳以上")

    case age == 0:
        println("0歳")

    default:
        println("18歳未満かつ0歳ではない") // 18歳未満かつ0歳ではない
    }
}
```

``default``はいずれの``case``にも該当しない場合に実行される。

### fallthrough

```go
package main

func main() {
    switch age := 21; {
    case age >= 20:
        fallthrough

    case age >= 18:
        println("18歳以上") // 18歳以上

    case age == 0:
        println("0歳")

    default:
        println("18歳未満かつ0歳ではない")
    }
}
```

``fallthrough``を使って次のcaseを実行している。

## for(繰り返し処理・反復処理)

### 繰り返し処理

```go
package main

func main() {
    for i := 0; i < 10; i++ {
        println(i) // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    }
}
```

``for 初期化; 条件; 後条件 {なんらかの処理}`` と書くことができる。
順番としては``i := 0`` -> ``i < 10`` -> なんらかの処理 -> ``i++`` -> ``i < 10`` -> ...

``i``は``for``の中でしかアクセスできない。変数を宣言するところと条件のところなどをセミコロン(;)で区切る。

Go 1.22.0からは以下の書き方ができるようになった。

```go
package main

func main() {
    for i := range 10 {
        println(i) // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
    }
}
```

なお初期化や条件などを書かなければ無限ループを作成できる

```go
package main

func main() {
    for {
        // なんらかの処理
    }
}
```

他の言語では見かけたりする``while``がGo言語では``for``で行うことができる。

### 条件付きループ

```go
package main

func main() {
    i := 0

    for i < 10 {
        println(i) // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

        i++
    }
}
```

``for 条件 {なんらかの処理}``と書くことができる。こうすることで他の言語の``while``みたいな機能を補うことができる。

### map, slice, array(連想配列, スライス, 配列)

```go
package main

func main() {
    fruits := []string{"apple", "banana", "orange"}

    for i, v := range fruits {
        println(i, v) // 0 apple, 1 banana, 2 orange
    }

    countryCode := map[string]string{"1": "America", "81": "Japan"}

    for k, v := range countryCode {
        println(k, v) // 1 America, 81 Japan
    }
}
```

``i``はそのスライスのインデックス番号で、``v``はその値になる。
変数名はなんでもいいが、慣習として``i``や``j``(slice, array)が用いられる。

もしもどちらか必要がなければ``_``を使用しなければならない

```go
package main

func main() {
    fruits := []string{"apple", "banana", "orange"}

    for _, v := range fruits {
        println(v)
    }
}
```

### ネストされたfor

```go
package main

func main() {
    for i := 0; i < 10; i++ {
        for j := 0; j < 10; j++ {
            println(i, j) // 0 0, 0 1, 0 2, 0 3, 0 4, 0 5, 0 6, 0 7, 0 8, 0 9, 1 0, 1 1,...
        }
    }
}
```

### break

```go
package main

func main() {
    for i := 0; i < 10; i++ {
        println(i) // 0, 1, 2, 3
    
        if i == 3 {
            break
        }
    }
}
```

``break``はループを終了することができる。

```go
package main

import "fmt"

func main() {
LOOP: 
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if i == 1 {
				break LOOP
			}
			fmt.Println(i, j) // 0 0, 0 1, 0 2, 0 3, 0 4, 0 5, ..., 0 9
		}
	}
}
```

``LOOP``というラベルを作成した。ここの名前はなんでも良い。抜け出したい``for``の直前に書くとよいだろう。このコードの場合、LOOP でラベル付けされた for 文内の処理を抜けることを``break LOOP``は意味している。

### countine

```go
package main

func main() {
    for i := 0; i < 10; i++ {
        if i == 3 {
            continue
        }

        println(i) // 0, 1, 2, 4, 5, 6, 7, 8, 9
    }
}
```

``continue``はそれ以降の処理を飛ばし次のループに移行することができる。