前準備や基本情報
パッケージ管理
ターミナルで実行。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