Golang 環境構築時のメモ


# 概要
- golang の学習を始めるにあたり手元で go開発環境の整備を行った時のメモ
- 改訂2版 みんなのGo言語 (https://www.amazon.co.jp/dp/4297107279) を参考にしました

# 前提
- mac環境での構築例

# この記事でやっていること
- go 本体を導入する
- GOROOT GOPATHについて確認する
- hello world してみる
- gore 等のパッケージ導入をしてみる
- ghq + peco を導入する

# golang 開発環境の構築

## goのインストール
- 公式サイトを確認 https://golang.org/dl/
- macでbrewを用いる場合
```
> brew install go
> go version
go version go1.19.3 darwin/arm64
```
- 以後 go1.19.3 での事例

## GOROOT設定
- GOROOTは`go env GOROOT` で確認できる。
- goのインストールパスのことをGOROOTと呼ぶ。
- 以前はGOROOTは環境変数に設定する必要があったが、最近はGoのバイナリにGOROOT情報が含まれるため明示的に環境変数を指定する必要は無いらしい。
- インストールディレクトリを自分で変更した場合は GOROOT環境変数で指定する必要がある。とのこと。
- brew でインストールした場合は `/usr/local/opt/go/libexec` になるっぽい

## GOPATH設定
- GOPATHは `go env GOPATH` で確認できる。
- GOPATH は`go get` で取得した外部パッケージのリソースが保存されるパス。
- 以前はGoの開発を GOPATH 以下で行うことが多かったが、現在はあまり気にする必要が無くなったらしい（書籍によると)
- デフォルトでは `$HOME/go`。環境変数GOPATHを設定することで上書きも可能。
- 外部パッケージのリソースは GOPATH配下に配置されるため $PATH を通しておく。
```
export GOPATH=$(go env GOPATH)
export PATH=$PATH:$GOPATH/bin
```
- shell の初期化ファイルに組み込むとよさそう (.zshrc や .bashrc)

# hello world してみる
- 適当なディレクトリで `hello-world.go` というファイルをエディタで作成する

```hello-world.go
package main

import (
	"fmt"
)

func main() {
	fmt.Println("Hello World")
}
```

## 実行
- 単一ファイルをbuildせずに実行する

```shell
> go run ./hello-world.go
Hello World
```

- 単一ファイルをbuildして、バイナリを実行する
```shell
> go build ./hello-world.go
> ./hello-world
Hello World
```

# go get によるパッケージの追加
- `go get`は PerlのCPANや Ruby のgem のようなパッケージをインストールするコマンド
- CPANやgemとは仕組みが異なり 中央サーバーを持たず、Git やMercurial等のリポジトリを直接参照する。とのこと

##  go get でgore をインストールしてみる
- gore というパッケージをインストールしてみる( https://github.com/x-motemen/gore )
- リポジトリのreadme に従いコマンドを実行します。
```shell
> go get github.com/x-motemen/gore/cmd/gore

> gore --version
gore 0.5.5 (rev: HEAD/go1.19.3)
```
- `go get`後のGOPATHの中を確認してみる
```shell
> ls $GOPATH
bin/ pkg/
```
- `bin/` には取得した実行形式のファイル、`pkg/` には取得したソースファイルが配置される
- `go get` で取得するパッケージの対応バージョンが古いと `pkg/`ではなく `src/` になる場合もある
```shell
> ls $GOPATH/bin
gore*

> ls $GOPATH/pkg/mod/github.com/x-motemen/gore@v0.5.5/
（省略）
```

# gore を試す
- `gore` は Goの代表的なREPL(Read-eval-print loop)、rubyの irb や pry Perl のreply のように対話的にプログラムを実行し評価を出力する環境。
- 開発者 motemenさんの記事 https://motemen.hatenablog.com/entry/2015/02/go-repl-gore
- "Hello World" の例
```shell
> gore -autoimport
gore version 0.5.5  :help for help
gore> fmt.Println("Hello World")
Hello World
12
nil
gore>
```
- "Hello World"以後の表示、12 は 12バイト、nil は Printlnの戻り値を表している。12バイト出力され、エラーは無かったと読み取れる

### 追加のツール
- 参考にした書籍によると gore を便利に使うためにコード補完 `gocode` (https://github.com/mdempsky/gocode) 、プリティプリント `pp` (https://github.com/k0kubun/pp) というパッケージも導入すると良いとのことだった
- 今回の環境は goのバージョンが 1.19 のため `go get` ではエラーとなって困ったが `GO11MODULE=off`を環境変数に追加することで導入はできた
- 調べたところでは `GO11MODULE` は go1.11 から導入されたモジュールモードの指定。go 1.16以後ではデフォルトは on になっているようだった。
```shell
> GO111MODULE=off go get -u github.com/mdempsky/gocode
> GO111MODULE=off go get -u github.com/k0kubun/pp
```
- `ls $GOPATH` を確認すると pkg/ 以外に src/ ディレクトリが増えていた
```shell
> ls $GOPATH
bin/ pkg/ src/
```
- が、`gocode` は開発が終了しており `gopls`(https://github.com/golang/tools/blob/master/gopls )を使った方が良いらしいのでそちらも導入する
```shell
> go install golang.org/x/tools/gopls@latest
> gopls version
golang.org/x/tools/gopls v0.10.1
    golang.org/x/tools/gopls@v0.10.1 h1:JoHe17pdZ8Vsa24/GUO8iTVTKPh0EOBiWpPop7XJybI=
```
- とりあえず入ったっぽい

# ghq と peco の導入
- go開発に限らずghqとpecoを導入するとソース/プロジェクトの管理が楽になるので導入するとたいへん良い
- ghq (https://github.com/x-motemen/ghq), peco (https://github.com/peco/peco)
- 以下は macでの導入例。brew で簡単に導入できた
```shell
> brew install ghq
> brew install peco
```
- brewでのインストール後、下記のようなコードを .zshrc で`^ + ] キー`のショートカットをzshに登録することで ghq+peco をより便利に使うことができる
```shell
bindkey '^]' peco-src
function peco-src () {
  local selected_dir=$(ghq list -p | peco --query "$LBUFFER")
  if [ -n "$selected_dir" ]; then
    BUFFER="cd ${selected_dir}"
    zle accept-line
  fi
  zle -R -c
}
zle -N peco-src
```
- ghq + peco で検索するとたくさんの情報があるので参考にすると良さそう

# その他

## 環境変数の確認
- `go env` コマンドで環境変数を確認できる

```shell
> go env
GO111MODULE=""
GOARCH="arm64"
GOBIN=""
GOCACHE="$HOME/Library/Caches/go-build"
GOENV="$HOME/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="$HOME/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="$HOME/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/opt/homebrew/Cellar/go/1.19.3/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/opt/homebrew/Cellar/go/1.19.3/libexec/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.19.3"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/qg/t8bjybn92zz8sq7cb0lycmpr0000gn/T/go-build1237653337=/tmp/go-build -gno-record-gcc-switches -fno-common"
```

# 感想
- go開発入門環境としては上記で開発を開始できた。
- その他開発時にはエディタの補助ツールをいろいろ導入してカスタマイズするのが良さそう。
- `go get` `go install`周りは歴史的な話がいくつか出て来てコマンドが通らず困った場面もあった。パッケージの仕組みなどは調べる必要がありそう。
- バイナリをbuildせずに実行できる方法もあるのは知らなかった。