vscode-go で Workspace ごとに Go のバージョンを使い分ける

[vscode-go](https://github.com/golang/vscode-go) を使って Workspace (フォルダ) ごとに Go のバージョンを使い分ける方法をご紹介します。
[goenv](https://github.com/syndbg/goenv) のようなツールを使用しなくても Go と vscode-go の機能だけで簡単に複数バージョンを使い分けることができます。

※ こちらの記事に記載されている内容は [vscode-go v0.25.0](https://github.com/golang/vscode-go/releases/tag/v0.25.0) 時点の情報になります。

## Go をインストールする

Go がまだインストールされていない場合は[公式のインストールガイド](https://golang.org/doc/install)に従ってインストールしておきます。

https://golang.org/doc/install

今回は 2021 年 5 月現在最新の 1.16.4 をインストールしました。

```console
$ go version
go version go1.16.4 linux/amd64
```

また、`$GOPATH/bin` にも PATH を通しておいてください。

```console
$ export PATH=$PATH:$(go env GOPATH)/bin
```

## 追加で別のバージョンの Go をインストールする

複数バージョンの Go をインストールして管理するとなると [goenv](https://github.com/syndbg/goenv) を使うのが定番ですが、実は Go の標準機能でもある程度可能です。

https://golang.org/doc/manage-install

例として Go 1.11.13 をインストールしてみます。

```console
$ go get golang.org/dl/go1.11.13
$ go1.11.13 download
Downloaded   0.0% (     3266 / 121068518 bytes) ...
Downloaded   2.9% (  3489776 / 121068518 bytes) ...
... (略) ...
Downloaded  99.9% (120994352 / 121068518 bytes) ...
Downloaded 100.0% (121068518 / 121068518 bytes)
Unpacking /home/frozenbonito/sdk/go1.11.13/go1.11.13.linux-amd64.tar.gz ...
Success. You may now run 'go1.11.13'
```

これで `go1.11.13` コマンドで Go 1.11.13 を使うことができるようになりました。

```console
$ go1.11.13 version
go version go1.11.13 linux/amd64
```

このとき Go 1.11.13 は `$HOME/sdk/go1.11.13` 以下にインストールされています。

```console
$ go1.11.13 env GOROOT
/home/frozenbonito/sdk/go1.11.13
```

## VSCode で Go のバージョンを切り替える

[vscode-go](https://github.com/golang/vscode-go) がインストールされた VSCode で Go プロジェクトを開くと、画面下部のステータスバーに vscode-go で使用される Go のバージョンが表示されます。
今回はデフォルトのバージョンとして 1.16.4 をインストールしたので `Go 1.16.4` と表示されています。

![vscodego_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/5549286f-3f92-0a19-5f06-0bbe5a9aba0a.png)

先ほどインストールした Go 1.11.13 にバージョンを切り替えてみましょう。
ステータスバーの `Go 1.16.4` の部分をクリックします。

下図のようにコマンドパレットが表示されるので `Choose Go Environment` を選択します。

![vscodego_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/02dd401d-0188-c6a7-8ac8-e6de87ea8d02.png)

今度は利用できる Go のバージョン一覧が表示されるので、先ほどインストールした Go 1.11.13 を選択します。

![vscodego_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/57e9feba-80c9-df3b-e0f0-3ddf4bc268d2.png)

画面の指示に従ってリロードします。

![vscodego_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/90fbf39d-1024-b8a0-04f4-64ae690d8645.png)

ステータスバーの表示が `Go 1.11.13` に変わりました :tada: 

![vscodego_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/d47344ef-72ea-c5b3-8080-c5221fda0975.png)


試しに次のようなテストをコマンドパレットから `Go: Test File` を叩いて実行してみます。

```golang:main_test.go
package main_test

import (
	"runtime"
	"testing"
)

func TestGoVersion(t *testing.T) {
	version := runtime.Version()
	expected := "go1.11.13"
	if version != expected {
		t.Errorf("version is not %s, but %s", expected, version)
	}
}
```

![vscodego_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/7c479119-7dd1-09f2-afef-7389e2ea3b71.png)

ばっちり Go 1.11.13 で実行されていることが確認できました。

素晴らしいことにターミナルにもいい感じに PATH が通されていて、`go` コマンドで Go 1.11.13 が使えるようになっています。
(最近の VSCode はリロードしてもターミナルのプロセスが死なずに維持されるので、Go のバージョンが変わっていない場合はターミナルを閉じて再起動しましょう)

![vscodego_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/030cc51d-dac9-4bd1-eaac-c64946e23393.png)

選択した Go のバージョンは Workspace (フォルダ) 単位で記憶されるため、VSCode を閉じても再度開けば Go 1.11.13 が使える状態になっています。
デフォルトのバージョンに戻したい場合は `Choose Go Environment` で `Clear selection` を選択します。

![vscodego_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/58eb9a7b-f724-2989-b21f-a6859fe551b3.png)

また、直近 2 つ分のメジャーリリースの最新バージョンであれば VSCode 上で直接インストールすることも可能です。
`Choose Go Enviromnent` で `go get golang.org/dl/go1.x.x` と表示されている Go バージョンを選択することで対象のバージョンがインストールされます。

![vscodego_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586035/9a8f61fa-9381-edc5-ce45-540dbdee9cd1.png)

## 参考

https://github.com/golang/vscode-go/blob/v0.25.0/docs/ui.md#managing-your-go-version