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


前準備や基本情報

パッケージ管理

ターミナルで実行。go.modファイルが作成される。

go mod init github.com/${GITHUB_USER}/${PROJECT_NAME}

あとは go get するだけ。

実行環境(docker)

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

Dockerfile
FROM golang:alpine

WORKDIR /go/src/app

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

COPY . .
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: パッケージ内でのみ呼び出せる。先頭は小文字。
var PublicVariable string = "Public" // 呼び出せる
var privateVariable string = "private" // 呼び出せない
  • ファイル名はスネークケース ex. line_api.go

基礎文法

strconv パッケージ

string型と基本的なデータ型との間の変換をするパッケージ

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

スライスのmakeとcap

cap: メモリに確保してる分

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=[]
s1 := make([]int, 0) // 空のスライスをメモリに確保する(mapも同様)
var s2 []int // nil(メモリに確保しない。mapも同様)

スライスは配列への参照のようなもの

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

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(辞書型)

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

可変長引数

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

// 条件のみ
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)します。

// 通常
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()すると強制終了しなくなる!

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://xblood.hatenablog.com/entry/2019/01/28/213223

part2