Golangのユースケース
Template Literal
変数を文字列内で展開する。
JavaScriptでいう以下のようなことをしたい。
name = "John"
file_name = `${name}.csv`
実現方法
Sprintf
を使うのが一番しっくりきた。
hello := "Hello"
greet := fmt.Sprintf("%s World!\n", hello)
参考資料
JSONの取扱
Structで定義
以下のようにstructで型を定義して、それに従ってUnmarshallでパースする。
このやり方だと型情報が入るので、IDEの補完なども使える。
structの定義にはJSON-to-Go: Convert JSON to Go instantly が便利。
type beer struct {
ID string `json:"id"`
Fields struct {
Name string `json:"Name"`
NameEn string `json:"NameEn"`
Description string `json:"Description"`
...
}
type beerList struct {
Records []struct {
beer
}
Offset string `json:"offset"`
}
data := new(beerList)
if err := json.Unmarshal(body, data); err != nil {
fmt.Println("JSON Unmarshal error:", err)
return
}
fmt.Println(data.Records[0])
for i, v := range data.Records {
fmt.Println(i, v)
fmt.Println(v.Fields.Name)
}
interfaceで定義
interfaceを定義することで任意のデータを読み込むことができる。
var a interface{}
err = json.Unmarshal([]byte(body), &a)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", a)
取得したJSONデータについては以下のようにアクセスできる。
b := a.(map[string]interface{})["records"]
fmt.Println(b)
参考資料
コマンドラインで起動するアプリケーションでの引数の扱い
まず、コマンドライン引数の渡し方として以下2つがある。
- Flagを使わない場合
-
go run main.go 123 456
のように値だけを渡す
-
- Flagを使う場合
-
go run main.go -a=123 -b=456
のようにキーバーリューの形で渡す。
-
Flagとは上記の例からわかるように
flag package - flag - pkg.go.dev
Flagとは
Flagという言葉にピンときていませんでしたが、Wikipediaに記載されているようにCLIで起動するプログラムで動作を変えるオプションのことを一般的にフラグともいうようです。
なので、flag packageもGolang独自の用語でもなんでもなく、プログラミング一般で使われるフラグの用途として使うためのスタンダードライブラリということのようです。
コマンドラインオプションまたは単にオプション(フラグまたはスイッチとも呼ばれる)は、コマンドの動作を変更するもので、その効果はコマンドのプログラムによって決定されます。オプションは、コマンドライン上のコマンド名の後に、スペースで区切られた形で続きます。
Command-line interface - Wikipedia をDeepLにて和訳
使い方
以下3つの方法があるっぽい。
- F全てをまとめて取得する方法
- 特定の要素を取得する方法
- フラグを定義して取得する方法
Go公式に記載されている以下の例は「フラグを定義して取得する方法」を使っている。
import "flag"
var nFlag = flag.Int("n", 1234, "help message for flag n")
Flagを使わない
全ての引数をまとめて取得
func main() {
flag.Parse()
args := flag.Args()
fmt.Println(args)
}
# 何も指定しない場合
% go run not_flag.go
[]
# 複数の引数を渡す場合
% go run not_flag.go 123 456
[123 456]
要素を指定して取得
func main() {
flag.Parse()
fmt.Println(flag.Arg(0), flag.Arg(1))
}
% go run not_flag_select.go
% go run not_flag_select.go 123
123
% go run not_flag_select.go 123 456
123 456
% go run not_flag_select.go 123 456 789
123 456
Flagを使う
flag.Int
やflag.String
のように型名でFlagの定義を行なった後、flag.Parse
を実行することで定義した変数に値が格納される。
注意点として、ドキュメントに記載があるようにポインタが返ってくる。
Flags may then be used directly. If you're using the flags themselves, they are all pointers; if you bind to variables, they're values.
flag package - flag - pkg.go.dev
func main() {
var nFlag = flag.Int("n", 1234, "help message for flag n") // Flag名、デフォルト値、メッセージ
flag.Parse()
fmt.Println(*nFlag)
}
実際の動作としては以下の通りで、Flagが指定されない場合はデフォルト値が入る
# 引数に何も指定しない場合
% go run flag.go
1234
# 値だけを渡した場合
% go run flag.go 123
1234
# Flagの正しい形式で渡した場合
% go run flag.go -n=456
456
# 異なる型の値を渡した場合
% go run flag.go -n=0.3
invalid value "0.3" for flag -n: parse error
Usage of /var/folders/rc/74wzrts94h14rsn2z3lqmv3m0000gn/T/go-build1055359882/b001/exe/flag:
-n int
help message for flag n (default 1234)
exit status 2
Varを使った記載
型名Var()
を使って定義することもできる。
その場合には定義した変数にバインドされる。
func main() {
var nFlag int
flag.IntVar(&nFlag, "n", 1234, "help message for flag n")
flag.Parse()
fmt.Println(nFlag)
}
GitHub
参考資料
よく使う処理集
配列の流れを取得
len
を使う
arr := []int{1, 2, 3}
fmt.Println(len(arr)) // 3
配列
PaginationのあるAPIを繰り返し呼ぶ
GitHub Actionsでの静的解析
Linterの種類
- govet
- gofmt
プラクティス
- golangci-lintを使うのが良さそう。Actionsも提供されている。
- PRにはreviewdogとgolangci-lintを組み合わせればいいかな
golangci-lint
以下がとりあえずgolangci-lintを動かすために必要な最低限のもの。
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Gp
uses: actions/setup-go@v2
with:
go-version: 1.17
- name: golangci-lint
uses: golangci/golangci-lint-action@v2
with:
# Optional: working directory, useful for monorepos
working-directory: twitter
これでプッシュすると以下のように解析が走って問題があれば落ちる。
reviewdog
filter_mode: nofilter
を指定すると、差分以外に対する指摘もAnnotationとして表示される。
逆にこの指定をしない(デフォルト)だと差分に問題がなければチェックはパスする。
name: lint-mr
on:
pull_request:
types: [opened, synchronize]
jobs:
golangci-lint:
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: golangci-lint
uses: reviewdog/action-golangci-lint@v2
with:
# # Optional: working directory, useful for monorepos
workdir: twitter/
github_token: ${{ github.token }}
filter_mode: nofilter
以下のように問題のある箇所にコメントを表示してくれる。
参考資料
- reviewdog-golangci-lint を使う
- GitHub Actions で Go パッケージの CI 作業を一通り行う
- reviewdog/action-golangci-lint: Run golangci-lint with reviewdog
- reviewdogによるGoのコードレビュー - DeNA Testing Blog
- GitHub Actions で Go言語の lint と test を実行する | DevelopersIO
- goの静的解析ツールをGithub Actionsのv2で動かしてみた - Qiita
- ReviewdogのGitHub ActionsでGoのlintをかけてPRに表示する - sambaiz-net
- golangci-lintを理解する