Golang 基礎 (環境構築など) part1


# 前準備や基本情報
## パッケージ管理
ターミナルで実行。go.modファイルが作成される。

```
go mod init github.com/${GITHUB_USER}/${PROJECT_NAME}
```
あとは go get するだけ。

## 実行環境(docker)
main.goがあるディレクトリに以下を置く。(go.sumは１回でもgo getしてる場合のみCOPYする)

```dockerfile:Dockerfile
FROM golang:alpine

WORKDIR /go/src/app

COPY go.mod .
# COPY go.sum . 
RUN go mod download

COPY . .
```
```yml:docker-compose.yml
version: "3.7"

services:
  goapp:
    build: .
    tty: true
    volumes:
    - .:/go/src/app
```
以下のコマンドでコンテナの中に入る。(goappはサービス名)

```
~% docker-compose up -d
~% docker-compose exec goapp /bin/ash
```
コンテナ内でmain.goを実行。

```
/go/src/app # go run main.go
```

## publicとprivate
- 命名規則で判別。(変数名、関数名など)そのため、基本的にキャピタルケースorパスカルケースで命名する。
 - public: 他のパッケージからでも呼び出せる。先頭を大文字にする！
 - private: パッケージ内でのみ呼び出せる。先頭は小文字。

```golang
var PublicVariable string = "Public" // 呼び出せる
var privateVariable string = "private" // 呼び出せない
```

- ファイル名はスネークケース　ex. line_api.go

# 基礎文法
## strconv パッケージ
[string型と基本的なデータ型との間の変換をするパッケージ](https://golang.org/pkg/strconv/)

```golang
i, err := strconv.Atoi("-42") // stringからintへ
s := strconv.Itoa(-42)  // intからstringへ
```

## スライスのmakeとcap
cap: メモリに確保してる分

```go
m := make([]int, 5)
n := make([]int, 0, 5)
fmt.Printf("len=%d cap=%d value=%v\n", len(m), cap(m), m) // len=5 cap=5 value=[0 0 0 0 0]
fmt.Printf("len=%d cap=%d value=%v\n", len(n), cap(n), n) // len=0 cap=5 value=[]
```

```golang
s1 := make([]int, 0) // 空のスライスをメモリに確保する（mapも同様）
var s2 []int // nil(メモリに確保しない。mapも同様)
```

## スライスは配列への参照のようなもの
スライスはどんなデータも格納しておらず、単に元の配列の部分列を指し示しています。
スライスの要素を変更すると、その元となる配列の対応する要素が変更されます。
同じ元となる配列を共有している他のスライスは、それらの変更が反映されます。

```golang
names := [4]string{
	"John",
	"Paul",
	"George",
	"Ringo",
}
fmt.Println(names)  // [John Paul George Ringo]

a := names[0:2]
b := names[1:3]
fmt.Println(a, b)  // [John Paul] [Paul George]

b[0] = "XXX"
fmt.Println(a, b)  // [John XXX] [XXX George]
fmt.Println(names)  // [John XXX George Ringo]
```

## map(辞書型)

```golang
m := map[string]int{"apple": 100, "banana": 200}
fmt.Println(m["nothing"]) // 0

m["orange"] = 300    // 要素の追加
delete(m, "orange")  // 削除

v, ok := m["apple"] // 2つ目の返り値は受け取らなくてもおっけい
fmt.Println(v, ok) // 100 true
```

## 可変長引数
```golang
func foo(params ...int) {
	fmt.Printf("len=%d params=%v\n" , len(params), params)
	for _, param := range params {
		fmt.Println(param)
	}
}
func main() {
	foo() // len=0 params=[]
	foo(1, 2) // len=2 params=[1 2]

	s := []int{1, 2, 3}
	foo(s...) // len=3 params=[1 2 3]
}
```

## forとrange
```golang
// 条件のみ
sum := 1
for sum < 500 {
    sum += sum
}
fmt.Println(sum)

// 無限ループ
for {
    fmt.Println("hello")
}

// range
l := []string{"python", "go", "java"}
for index, value := range l{
    fmt.Println(index, value)
}

m := map[string]int{"apple": 100, "banan": 200}
for key, value := range m{
    fmt.Println(key, value)
}
for key := range m{
    fmt.Println(key)
}
for _, value := range m{
    fmt.Println(value)
}
```

## swicth
switch caseは、上から下へcaseを評価します。 caseの条件が一致すれば、そこで停止(自動的にbreak)します。

```golang
// 通常
os := "mac"
switch os {
case "windows":
	fmt.Println("windows!!")
case "mac":
	fmt.Println("mac!!")
default:
	fmt.Println("linux!!")
}
// 条件省略
t := time.Now()
switch {
case t.Hour() < 12:
	fmt.Println("morning")
case t.Hour() < 17:
	fmt.Println("afternoon")
default:
	fmt.Println("foooo")
}
```


## panicとrecover
panicで強制終了してしまう処理の前にdeferでrecover()すると強制終了しなくなる！

```go
func thirdPartyConnectDB() {
	panic("Unable to connect database.")
}

func save() {
	defer func() {
		s := recover()
		fmt.Println(s)
	}()
	thirdPartyConnectDB()
}

func main() {
	save()
	fmt.Println("ok?")
}
```


## 参考
[現役シリコンバレーエンジニアが教えるGo入門 + 応用でビットコインのシストレFintechアプリの開発](https://www.udemy.com/course/go-fintech/)
https://xblood.hatenablog.com/entry/2019/01/28/213223

[part2](https://qiita.com/mi11km/items/8b336736ed66ec48705c)へ