Go言語 基礎知識集

# はじめに
- 私自身Go言語の勉強中で、更新前提で投稿していますので、はじめから全体を網羅できていないです。
- まだGoは新しい言語で、なかなかネット上にこれだ！という基本集のようなものがなかったので、自分用に色々なサイトの情報をまとめておいたものを投稿します。
- <font color="orange"><strong>はじめにざっくり理解したい場合におすすめです。</strong></font>

# 基本文法

## 型
### 型の種類
```
・文字列型
string  文字列を格納

・符号付き整数型
int8	-128 ～ 127 (8 bit)
int16	-32768 ～ 32767 (16 bit)
int32	-2147483648 ～ 2147483647 (32 bit)
int64	-9223372036854775808 ～ 9223372036854775807 (64 bit)
int	32 bit 処理系ならば int32, 64 bit 処理系ならば int64
・符号なし整数型
uint8	0 ～ 255 (8 bit)
byte	uint8 の別名
uint16	0 ～ 65535 (16 bit)
uint32	0 ～ 4294967295 (32 bit)
uint64	0 ～ 18446744073709551615 (64 bit)
uint	32 bit 処理系ならば uint32, 64 bit 処理系ならば uint64

・浮動小数点数型
float32	 ±1.1754944E-38 ～ 3.4028235E+38 (32 bit 単精度)
float64	 ±2.22507E-308 ～ 1.79769E+308 (64 bit 倍精度)

・複素数型
complex64   float32 の実数部と虚数部を持つ複素数
complex128  float64 の実数部と虚数部を持つ複素数

・真偽値型
bool  真（true）または偽（false）を格納する型
```

### 型の初期値
- 型付きで変数を宣言し、何も代入しなかった際の初期値

```.go
int      : 0
float32  : 0
bool     : false
string   : ""
complex64: (0+0i)
```

### 型の書式
- 後述しますが、fmtパッケージに存在するPrintf関数は書式を指定して書き込みを行います。よくわからなかったら必要になる時までみなくて大丈夫です。

```.g
%v	デフォルトフォーマットを適用した値 構造体を出力する際、+フラグ(%+v)を加えるとフィールド名が表示される
%#v	この値をGo言語の構文で表現する
%T	この値の型をGo言語の構文で表現する

・論理値
%t	単語、trueまたはfalse

・整数
%b	基数2
%c	対応するUnicodeコードポイントによって表される文字
%d	基数10
%o	基数8
%x	基数16、10以上の数には小文字(a-f)を使用
%X	基数16、10以上の数には大文字(A-F)を使用
%U	ユニコードフォーマット: U+1234; "U+%x"と同じ。デフォルトは、4桁

・浮動小数と複素数
%e	科学的記数法、例: -1234.456e+78
%E	科学的記数法、例: -1234.456E+78
%f	指数なしの小数、例: 123.456
%g	%e、%fのどちらか出力の短い方
%G	%E、%fのどちらか出力の短い方

・文字列とバイト型のスライス
%s	文字列またはスライスそのまま
%q	Go言語の構文に従いダブルクォート形式でエスケープ
%x	各バイトを2文字の16進数文字列として

・ポインタ
%p	16進数文字列、先頭に0x
```

## 変数

### 宣言方法
```.go
var a int
var a int = 10
var b float64 = 1.234
var c float64 = 5.678
var e, f int = 1, 2
```

### 型推論
- 丁寧に型を宣言しなくても、暗黙的に型を決めてくれます。(ローカル変数のみに使用可能)

```.go
variable := "" // string型になる
```

## 定数
```.go
const title = "Go"

// iota を使用すると連番を代入できる
const (
    foo = iota   // foo = 0
    bar          // bar = 1
    baz          // bar = 2
)
```


## 配列
- Go言語の場合、他の言語で用いられる配列とは少し違い、基本的には固定長です。

```.go
var a [4]int           // [0,0,0,0]
b := [5]int64{1, 2, 3} // [1,2,3,0,0]
 

c := [3][3]int{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
}
```


## スライス
- こちらの方が他の言語で多く使われる配列に近そう。(`配列`と`スライス`の違いはそれぞれ解釈が違うような気がします。内部的にどうなっているかある程度理解していればいいと思います。)

```.go
a := []int{1, 2 ,3, 4}
b := []int{1, 2, 3, 4, 5, 6, 7, 8}

c := b[2:6]  // [3,4,5,6]

a = append(a, 5)

fmt.Println(a["3"]) // 3
fmt.Println(a["5"]) // 5 

// S[start:end]	start から end - 1 まで
// S[start:]	start から最後尾まで
// S[:end]	先頭から end - 1 まで
// S[:]	先頭から最後尾まで


// len(S) 長さ
// cap(S) 容量 *省略して宣言すると、長さと同じになる
// ptr(S) ポインタ
// make(type, len, [cap]) type型で、長さlenで、容量capであるスライスを生成
// append(S, x1, x2, ...) 末尾にx1, x2, ... を追加
```


## マップ
- phpでいう連想配列です。インデックスが連番ではなく指定ができる配列です。

```.go
var a map[string]int = map[string]int{"foo": 10, "bar": 20}
fmt.Println(a["foo"])  // 10

b := make(map[string]int)
delete(b, "baz")
v, ok := b["baz"]

// make() 空のマップを生成
// delete() マップから特定のキーの値を削除
// value, ok = map[key] 特定のキーの存在チェック
```


## 配列とスライスの注意点
- 以下の記事の概要を載せさせていただきます。ざっくりなので、元記事見ていただいた方が図もあってわかりやすいと思います。  
[Goのarrayとsliceを理解するときがきた]( https://qiita.com/seihmd/items/d9bc98a4f4f606ecaef7)

```
・ arrayは実体的な値である。
    arrayはメモリ上にある"値を参照する"ものではなく"値そのもの"として取り扱う。
    値そのもの、というのは例えばint型変数を扱うときにわざわざ参照とか考えないように、
    arrayも[3]intならintが３つ並んだ値として考えるという感じ。
    [3]intと[4]intは別の型であり互いに代入することはできない。
    ------------------------------------------------------------
    a := [3]int{1, 2, 3}
    b := a

    // メモリ上で別の位置にある
    fmt.Println(&a[0]) // 0xc8200122e0
    fmt.Println(&b[0]) // 0xc820012300

    b[0] = 0
    fmt.Println(a) // [1 2 3]
    fmt.Println(b) // [0 2 3]
    ------------------------------------------------------------

・ sliceはarrayへの参照を持つデータ構造である
    slice変数をつくってもそれ自体が値を保持しているわけではない。
    だからGoのコードで何気なくsliceを作ったときもその裏側では実体としてのarrayが作られている。
    ------------------------------------------------------------
    s1 := []int{1,2,3}
    s2 := s1
    s2[1] = 0

    // 同じarrayを参照しているから当然の結果
    fmt.Println(s1) // [1 0 3]
    fmt.Println(s2) // [1 0 3]
    ------------------------------------------------------------

・ slicing
    slicingはarrayを新たに参照しているだけなので、新しくメモリを確保するわけではない
    二度目のslicingではsliceからそれ自体よりも大きいsliceを切り取っている（ように見える）が、参照し直しているだけ。
    ------------------------------------------------------------
    a := [3]int{1, 2, 3}
    s := a[0:2]
    fmt.Println(s) // [1 2]
    s = s[0:3]
    fmt.Println(s) // [1 2 3]
    ------------------------------------------------------------

・ append
    appendを使用することでsliceを「可変長な」配列として扱っているつもりだったが、
    sliceが「一定のサイズを持った」arrayを参照していることを考えるとおかしな話でもある。
    実際裏側では、単にメモリ上で新たなarrayをallocateしている。(capが足りない場合のみ)
    そうでなければそもそも s = append(s, 1) のようにappendの結果を変数に代入する必要がない。
    ------------------------------------------------------------
    s := []int{1}
    t := append(s, 2)

    // sとtは別のarrayを参照する
    fmt.Println(&s[0]) // 0xc82000a310
    fmt.Println(&t[0]) // 0xc82000a330

    // だから一方を変更しても影響しない
    t[0] = 0
    fmt.Println(s) // [1]
    fmt.Println(t) // [0 2]
    ------------------------------------------------------------
```



## if文
```.go
if a < 10 {
    a++   
}

// 条件式の前に処理を書くことができる
if i := 0; i == 0 {
    fmt.Println("zero")
} else {
    fmt.Println("not zero")
}

// 論理演算子
// !x, x && y, x || y
```


## for文
- 他の言語ではループ用の制御文がいくつかあるが、Goでは`for`のみを使用する

```.go
for i := 0; i < 10; i++ {
    fmt.Println("hello, world")
}

// while文的な使い方
for i <= 10000 {
    sum += i
    i++
}
```


## range節
- 配列、スライス、マップに対してのforeach的役割で、複数の格納データ全てに対して処理を行える。

```.go
a := []int{1, 2, 3, 4, 5}
for i, v := range a {
    fmt.Println(i, v)
}

b := map[string]int{"foo": 10, "bar": 20, "baz": 30}
for k, v := range b {
    fmt.Println(k, v)
}
```


## switch文
```.go
switch i % 15 {
case 0: fmt.Print("FizzBuzz")
case 3, 6, 9, 12: fmt.Print("Fizz")
case 5, 10: fmt.Print("Buzz")
default: fmt.Print(i)
}
```

# 基礎知識

## import句
- Go言語は、使用するパッケージをファイルのはじめに宣言します。ちなみに、`import`したものの、使用していないパッケージがあるとコンパイルエラーが起きます。(変数等も同じで、Go言語の大きな特徴のひとつ)

```.go
import (
    "fmt"
    "strings"
)
```

## mainパッケージ
- mainパッケージ内のmain関数からプログラムの実行が開始され、多くの場合これが`main.go`に記述されています。

```go:main.go
package main


func main() {
      //
}
```


## メソッド
```.go
func square(x int) int {
    return x * x
}

func main() {
    fmt.Println(square(10))
}
```

## メソッドの返り値
- 返り値を複数指定可能

```.go
func divMod(x, y int) (int, int) {
    return x / y, x % y
}
func main() {
    p, q := divMod(10, 3)
}

// 返り値に変数名を指定することで、returnの後に明示的に返り値を指定しなくて良い
func divMod(x, y int) (p, q int) {
    p, q = x / y, x % y
    return
}
```

## メソッドの引数
```.go
// 仮引数を可変長にしたい場合
func foo1(a int, args ...int) {
    fmt.Println(a, args)
}

func foo0(args ...int) {
    fmt.Println(args)
}

func main() {
    foo0()            // []
    foo0(1)           // [1]
    foo0(1, 2)        // [1 2]
    foo0(1, 2, 3)     // [1 2 3]
    foo1(1)           // 1 []
    foo1(1, 2)        // 1 [2]
    foo1(1, 2, 3)     // 1 [2 3]
    foo1(1, 2, 3, 4)  // 1 [2 3 4]
}
```



## ローカル変数のスコープ
- スコープはブロック単位(自分以上のネストの深さで宣言されたものは有効)

```.go
func main() {
    x := 1
    {
        y := 2
        {
            z := 3
            fmt.Println(x)
            fmt.Println(y)
            fmt.Println(z)
        }
        fmt.Println(x)
        fmt.Println(y)
        // fmt.Println(z)  z は範囲外 (コンパイルエラー)
    }
    fmt.Println(x)
    //fmt.Println(y)    y は範囲外 (コンパイルエラー)
    //fmt.Println(z)    z は範囲外 (コンパイルエラー)
}
```


## 関数を引数にとる関数
```.go
// 2乗の値を返す
func square(x int) int {
    return x * x
}

// 3乗の値を返す
func cube(x int) int {
    return x * x * x
}

// nからmまでのそれぞれの2乗の和とそれぞれの3乗の和を求めたい

// ・メソッドを2つそれぞれ定義した場合
//
// // 2乗の和を返す
// func sumOfSquare(n, m int) int {
//     a := 0
//     for ; n <= m; n++ {
//         a += square(n)
//     }
//     return a
// }
// // 3乗の和を返す
// func sumOfCube(n, m int) int {
//     a := 0
//     for ; n <= m; n++ {
//         a += cube(n)
//     }
//     return a
// }
//
// func main() {
//    a := sumOfSquare(1, 3)
//    b := sumOfCube(1, 3)
//}


// ・メソッドを1つにまとめた場合
//
// 引数に関数をとることで、sumOfSquare, sumOfCubeを一つのメソッドにまとめられる
func sumOf(f func(int) int, n, m int) int {
    a := 0
    for ; n <=  m; n++ {
        a += f(n)
    }
    return a
}

func main() {
    a := sumOf(square, 1, 3)  // 14 = 1 + 4 + 9
    b := sumOf(cube, 1, 3)    // 36 = 27 + 8 + 1
}
```


## 匿名関数
```.go
square := func(x int) int { return x * x }
fmt.Println(square(10))

a := func(x int) int { return x * x }(10)
fmt.Println(a)
```


## クロージャ
```.go
func foo(n int) func(int) int {
    return func(x int) int { return x * n }
}

func main() {
    foo10 := foo(10)
    foo20 := foo(20)
    fmt.Println(foo10(1))
    fmt.Println(foo20(10))
}
```

# 更新をお待ちください
今回はここまでです。随時更新しますので、お待ちください。 
訂正等ございましたら、遠慮なくコメント欄でお願いいたします。
<font color="gree"><strong>最後まで読んでいただきありがとうございました！</strong></font>