goenvのインストールと使い方からGOPATH設定まで

Go言語の環境をgoenvで作るときのメモです。
特にGOPATHがgoenvのバージョンによって変わる問題があったので、その辺りをまとめました。
MacOSはCatalina 10.15.2です。

# goenvのインストール
GitかHomebrewでインストールできます。

#### Git

```
 $ git clone https://github.com/syndbg/goenv.git ~/.goenv
```

#### Homebrew

```
$ brew install goenv
```

`~/.zshrc` (あるいは `~/.bash_profile` )に追記

```~/.zshrc
export GOENV_ROOT=$HOME/.goenv
export PATH=$GOENV_ROOT/bin:$PATH
eval "$(goenv init -)"
```

編集内容を反映

```
$ source ~/.zshrc
```

# goenvのコマンド
インストールできるGoのバージョン一覧

```
$ goenv install -l
```

Goのバージョンを指定してインストール
(以下、1.15.3を例にする)

```
$ goenv install 1.15.3
```

インストールされているGoのバージョン一覧

```
$ goenv versions
```

グローバルで使用するバージョンを設定

```
$ goenv global 1.15.3
```

特定のディレクトリで使用するバージョンを設定

```
$ goenv local 1.15.3
```

# goenvのアップグレード

`goenv install -l`で欲しいGoのバージョンが出てこない時はgoenvのアップグレードが必要です。

これもGitかHomebrewでできる。

#### Git

```
$ cd ~/.goenv
$ git pull
```
(ブランチはmasterで`git pull`する)

#### Homebrew

```
$ brew upgrade goenv
```


# goenv自体のバージョンの切り替え

goenvは1系と2系がある。
2系は2020年12月時点でベータ版なので、どちらを使うか悩むところです。
これについては後ほど書いています。
最終的にはここに落ち着きました。
[goenvのおすすめ設定](#おすすめ設定)

バージョンはこれで確認できます。

```
$ goenv --version
```

バージョンを変えるには`~/.goenv`でブランチをタグで切り替えれば良いらしい。

```
$ cd ~/.goenv
$ git fetch
$ git tag
...
1.23.2
1.23.3
...
2.0.0beta10
2.0.0beta11
...
```

いろいろ出てくるので好きなタグを選べば良い。

```
$ git checkout 1.23.3
```

# goenvによるGOPATHの管理

ここからは込み入った話になります。
goenvではGOPATHの管理も行われるようになりました。

GOPATHとは外部パッケージが配置されるディレクトリのことで、デフォルトで`~/go`になります。

しかし、goenvはGOPATHを`~/go/{バージョン}`にすることを推奨しています。
`~/go`のままがいいなら、`~/.zshrc`にGOENV_DISABLE_GOPATHを1(有効)にすることで実現できます。

```~/.zshrc
GOENV_DISABLE_GOPATH=1
```

GOENV_DISABLE_GOPATHについては、公式のGithubに詳しい記載が載っています。
https://github.com/syndbg/goenv/blob/master/ENVIRONMENT_VARIABLES.md
> Disables management of GOPATH.
Set this to 1 if you want to use a GOPATH that you export. It's recommend that you use this (as set to 0) to avoid mixing multiple versions of golang packages at GOPATH when using different versions of golang. See https://github.com/syndbg/goenv/issues/72#issuecomment-478011438

違うGoのバージョンでダウンロードしたパッケージはごちゃ混ぜにしたくないので、なるべくGOENV_DISABLE_GOPATHは0のままにしておいてとのこと。

これには納得なのですが、goenvのバージョンによって挙動が違いました。

|    |  パッケージの配置ディレクトリ  |
| ---- | ---- |
|  2.0.0beta6 以降  |  ~/go/{バージョン}/pkg  |
|  2.0.0beta5 以前  |  ~/go/pkg |

goenvは[2.0.0beta6](https://github.com/syndbg/goenv/blob/master/CHANGELOG.md#200beta6)からGOPATHの管理が変わったようでその影響と思われます。

ちなみにこれは`~/.zshrc`のGo関連が以下の時の挙動です。

```~/.zshrc
export GOENV_ROOT=$HOME/.goenv
export PATH=$GOENV_ROOT/bin:$PATH
eval "$(goenv init -)"
```

<font color="red">※設定ファイルにその他のGo関連のPATH記載があると違ってくる可能性があります。</font>

# Go Modulesでパッケージをダウンロード

Go Modulesを使った場合にパッケージがどこにダウンロードされるかを見ていきます。
Go Modulesについては[こちらの記事](https://qiita.com/propella/items/e49bccc88f3cc2407745)が参考になります。

#### goenv 2.0.0beta11の場合

```
$ goenv --version
goenv 2.0.0beta11
```

前提としてグローバルバージョンは1.15.3にします。

```
$ goenv global 1.15.3
```

test_appを作って、ローカルバージョンを1.14.9にします。

```
$ mkdir test_app
$ cd test_app
$ goenv local 1.14.9
```

Go Modulesでパッケージを管理します。

```
$ go mod init test_app
```

main.goを作成して、`rsc.io/quote`というパッケージを使用します。
https://pkg.go.dev/rsc.io/quote

```main.go
package main

import (
    "fmt"
	
    "rsc.io/quote"
)

func main() {
    fmt.Println(quote.Hello())
}
```

ビルドして実行します。

```
$ go run main.go
go: downloading rsc.io/quote v1.5.2
go: downloading rsc.io/sampler v1.3.0
go: downloading golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
こんにちは世界。
```

`rsc.io/quote`がダウンロードされて、quote.Hello()の戻り値である`こんにちは世界。`が出力されました。
`rsc.io/quote`はどこに配置されているかというと`~/go/1.14.9/pkg/mod`です。
ちゃんと`goenv local 1.14.9`で指定したバージョン下に配置されました。

これと同様の処理をgoenv 2.0.0beta5以前で行うと、バージョンは関係なく`~/go/pkg/mod`にパッケージがダウンロードされます。

# おすすめ設定

GOPATHにをどこにしたいかでgoenvのバージョンを決めるのが良さそう。

- `~/go/{バージョン}`にしたいならgoenv 2系ベータ版最新
- `~/go`でいいならgoenv 1系最新
- 任意に設定したい場合はgoenv 1系最新で`GOENV_DISABLE_GOPATH=1`を`~/.zshrc`に記載

特にこだわりがないならgoenvの方針に従って2系ベータ版最新にすると良いと思います。

2系がベータ版でなく正式にリリースされればGOENV_DISABLE_GOPATH=1だけで切り替えれば良さそうです。