他言語から来た人がGoを使い始めてすぐハマったこととその答え

# 環境構築するまでに知りたかったこと

## Golangの最新バージョンは？

1.16.6 (2020/07/12リリース)

https://golang.org/doc/devel/release.html

## Goのインストール方法は?

macOS の場合は brew で OK

```
$ brew install go
```

この場合、goのsdkは `/usr/local/Cellar/go/<バージョン>/libexec` にインストールされます。 IntelliJ IDEA や GoLand にような IDE に「GOROOT」というものの指定を求められたら、このパスを使います。

brew で入らないバージョンの go が必要だったり、いくつかのバージョンを併用したい場合は

```
$ go get golang.org/dl/go1.14.4
$ go1.14.4 download

# 1.xx.0 の場合
$ go get golang.org/dl/go1.15
$ go1.15 download

# 上記でgo getしたgo1.15等が見つからない場合、 `$GOPATH/bin` 以下を参照してください
# $GOPATH は go env | grep GOPATH で特定できます
```

これ以降、 `go1.14.4` を実行すると名前のとおり go 1.14.4 が利用できます。`1.14.4` のところは必要に応じて置き換えてください。

なお、この場合のGOROOTは `go env GOROOT` で確認できます。

```
$ go1.14.4 env GOROOT
/Users/mumoshu/sdk/go1.14.4
```

参照: https://golang.org/doc/install#extra_versions


## パッケージ管理ツールどれ使ったらいんだろう

2019年現在はほとんど `go` コマンドにも組み込まれている `go mod` (Go Modules) を使っているので、それを使いましょう。

2018年以降メンテされていないような古いプロジェクトはまだ `glide` や [dep](https://github.com/golang/dep) を使っていることがあるので、そういうプロジェクトをビルドする必要がある場合は、後述の手順を参考に `dep` や `glide` を使ってビルドしてください。go modはvgoはdepからの移行、またdepはglideからの移行が簡単にでまます。

go mod, godep, glideなどが無い時代からの慣習でvendoring([2014年の時点ではそれがベスト・プラクティスだったはず](http://qiita.com/umisama/items/c2a8db6c23db18dd5437#%E4%BE%9D%E5%AD%98%E6%80%A7%E7%AE%A1%E7%90%86))を好む人もいる。今でも多くの著名なプロジェクトでvendoringしている。

### vendoringするかどうかにかかわらず、パッケージ管理ツールは入れよう

vendoringするとしてもdepかglideは導入して「何をvendorに入れるか」ということはコード化しておいたほうがいいと思うので、パッケージ管理ツールは必須と思っておいたほうがよさそう。というか、Go 1.12以降は何もしなければ Go Modules を使うことになると思う。

どのツールでも vendoring は可能なので、それによって古いパッケージ管理ツールをあえて選択する必要もない。例えば Go Modulesなら `go mod vendor` で vendor を生成して、 `go build -mod=vendor` のように vendor を使ったビルドを実行することができる。

### Go Modules / vgo

Go 1.11から(Versioned) Go Modules (a.k.a その実装である `vgo`)が利用できるようになっている。 `vgo` が有効化された `go` を使うと、 `go build` のタイミングで勝手に必要なモジュールバージョンをダウンロードしてくれる。 `dep` 等だと `vendor` に該当モジュールをダウンロードする前提だったけど、 `vgo` の場合はデフォルトでは `vendor` を利用しない。`$GOPATH/go/mod` 以下にバージョニングされた状態でダウンロードされて、`vgo` を利用する全プロジェクトはそこを参照するようになる。ので、`vendor`を必ずしもgit commitしなくてもよい。

Go 1.11なら `GO111MODULES=on go build` のように `go` コマンドを実行すると利用できる。Go 1.12以降はデフォルトで `GO111MODULES=auto` の扱いとなっている。`auto` の場合は 後述する `GOPATH` 以下のディレクトリの場合は `vgo` が無効化され、 `GOPATH` の外なら `vgo` が有効化された状態になる。

## GOPATHどこにしたらいいの?

GOPATHは、git cloneしたパッケージや、go getしたパッケージ、自分がコードを変更する可能性のある・なしにかかわらず、vendor以外のパッケージすべてをインストールする先となるディレクトリ。

### Go 1.8以上

特に指定されていない場合は、

```
export GOPATH=$HOME/go
```

が設定されたものとみなされるようになった。

https://github.com/golang/go/issues/17262

基本的にはそのままでよくて、もしGOPATHを複数持ちたいのであれば、`export GOPATH=変更後のGOPATH`で切り替えればOK。

### Go 1.5以上

GOPATH設定してないと、go getすらできないけど…。
今まではプロジェクトルート以下に依存パッケージをgo getしたいからって、苦し紛れにプロジェクトルートやその配下をGOPATHにしたりしてた。

でも、どうやらvendorが来たGolang 1.5以上は、

* GOPATHはプロジェクトルート以外（ホーム以下とかでもOK）の適当なところに設定しておく(go getしたものはそこにインストールされる)
  * ついでに＄GOPATH/binをPATHに追加しておく(これでgo installで生成されたバイナリへのパスが通せる)
* プロジェクト毎に必要なパッケージはglide get（この時点ではGOPATHを変更する必要はなし)
* scaffoldingをするようなツールがGOPATH以下に生成したソースを置いてくれることがあるので、それで都合が悪い場合は`GOPATH=$(pwd)`→これはやめたほうがいいと思います
  * 例えば `bash -c "GOPATH=$(pwd); cobra init github.com/mumoshu/hoge"`
  * …でこの時はいいんだけど、GOPATHが変わらない前提でワークフローが組まれているツールがあると思う
  * 例えばcobra。`cobra init foo/bar`すると`$GOPATH/src/github.com/foo/bar`以下にソースが生成されて、以降の`cobra hoge`コマンドはそのディレクトリに`cd`した状態で実行される想定になっている。

ということでよさそう。

Rubyから来た人なら、この状態でgemコマンドと対応付けて覚えられそう。

`go get/install` → `gem install`
`glide get/install` → だいたい`Gemfileいじって、bundle install`
`glide update` → `bundle update`

## GOPATH以下ってどういう構成になってるはず?

自分がいま書いてるコードもGOPATH以下に置く、っていうのが他言語から来た人がハマるポイントだと思う。

```
$GOPATH
├─bin/
├─pkg/
│  └─darwin_amd64/
│    ├─github.com/
│    │  └─GitHubユーザ名
│    │    ├─`*.a`ファイル[^1]
│    │    └─GitHubレポジトリ名/`*.a`ファイル[^2]
│    └─pkg.in/
│      ├─パッケージ名/
│      └─`*.a`ファイル
└─src/
  ├─gopkg.in/
  │  └─パッケージ名/
  │    └─LICENSEとか`*.go`とかREADMEとか
  └─github.com/
    ├─GitHubユーザ名
    │  └─GitHubレポジトリ名/
    │    └─LICENSEとか`*.go`とかREADMEとか
    └─<あなたのGitHubユーザ名>
      └─GitHubレポジトリ名/
        ├─glide.yaml
        ├─main.go
        ├─その他、あなたが開発中のソフトウェアのコード
        └─vendor/依存先パッケージのコード(glideでとってきたやつ)
```

[^1]: なんでここに生成されてるのかがわかってない。GitHubレポジトリ名/main.goとかがあるとこのファイルにビルドされるのかな?
[^2]: srcからビルドしたバイナリっぽい。こうやって予めビルドしておくと、依存元プロジェクトから使いたい時に動的リンクでビルド時間をかけずにすぐ使える、ってことかな

## git cloneしてきたGoパッケージはどこに置くの?

### (最近少ない)自プロジェクトのサブパッケージを相対パスでimportしているプロジェクトの場合

GitHub上でforkした上で、`REPO=repo; git clone git@github.com:$YOUR_GITHUB_USER/$REPO.git $GOPATH/src/github.com/$YOUR_GITHUB_USER/$REPO`

forkする理由は、パッケージが被らないようにするため。既に`go get`でそのGoパッケージをGOPATH以下にインストールしてあった場合、forkしてないと`go get`したものも、`git clone`したものも両方`github.com/user/repo`インストールすることになっちゃうので、後でやったほうが失敗してしまう。

代案として、GOPATHは複数設定できるので、ふたつ目のGOPATH以下にgit cloneする・・みたいなのも考えたけど、その場合は`cobra`みたいにGOPATH以下にソースをscaffoldしてくれるツール(おそらくGOPATHに2つのパスが書かれていたら、最初の一つめ以下にscaffoldすると思う)と相性悪そうなのでやってない。

同じ結論が[【翻訳】プロダクション環境でのベストプラクティス - Qiita](http://qiita.com/umisama/items/c2a8db6c23db18dd5437#%E9%96%8B%E7%99%BA%E7%92%B0%E5%A2%83)に書いてあったけど、こういう理由でそうしてるのかは不明。

### (最近多い)自プロジェクトのサブパッケージを絶対パスをimportしているプロジェクトの場合

例えば以下のリンク先のように、

https://github.com/coreos/kube-aws/blob/v0.9.2-rc.4/config/config.go#L16-L19

* `github.com/coreos/kube-aws` というプロジェクトのサブパッケージが、
* 同プロジェクトの他のサブパッケージを"github.com/coreos/kube-aws/subpackage"のように絶対パスで

参照している場合、前述の方法でこれを`github.com/mumoshu/kube-aws`のようなfork先のパッケージ名にgit cloneすると、コンパイルできない。というか、fork元のパッケージがGOPATHにあったら、そちらをimportしていまう。

この場合は、二通り方法がある。一つは、「fork元とfork先をそれぞれ別のGOPATHへgit cloneする」。もう一つは「fork先はfork元の名前でgit cloneする」。

#### fork元とfork先をそれぞれ別のGOPATHへgit cloneする

もう何を言っているのかわからないかもしれないけど、以下のようなディレクトリ構造にするということ。
ディレクトリ名はわかりやすさのためにあえてダサくしたので、もっと良い名前があればそれを使ってください！または教えてください。

- Gopath4origin
    - src
        - github.com
            - coreos
                - kube-aws
- Gopath4fork
    - src
        - github.com
            - mumoshu
                - kube-aws

fork先を開発するときは、以下のようにfork先用に作ったGopathを$GOPATHに設定して、その下にある該当パッケージに移動して開発を進める。

```
export GOPATH=$HOME/Gopath4fork
cd $GOPATH/src/github.com/mumoshu/kube-aws
go build .
```

#### fork先はfork元の名前でgit cloneする

fork元が`github.com/coreos/kube-aws`で、fork先が`github.com/mumoshu/kube-aws`だったら、以下のようにfork元もfork先も`github.com/coreos/kube-aws`へgit cloneしてそこで開発をする、ということ。

```
mkdir $GOPATH/src/github.com/coreos
git clone git@github.com:mumoshu/kube-aws.git $GOPATH/src/github.com/coreos/kube-aws
cd $GOPATH/src/github.com/coreos/kube-aws
```

自分が普段開発するときは、remoteにはfork元とfork先の両方が常にある状態にしてます。

```
$ git remote
camilb
mumoshu
origin
```

上記の例だとoriginがfork元で、camilbが他の人のfork、mumoshuが自分のforkという状態にしてあります。例えば、他の人のforkは以下のように追加できますね。

```
$ git remote add camilb git@github.com:camilb/kube-aws.git
```

最初にcloneしたのがfork元レポジトリだった場合、originがfork元なので自分のforkを追加したくなりますよね。その場合は以下のようにできます。

```
# まだforkしてなかったら..
$ hub fork

$ git remote add mumoshu git@github.com:mumoshu/kube-aws.git
```

個人的には、この方法で困ってないので、こちらを推奨しておきます。

# コードを書き始めるまでに知りたかったこと

- 新規プロジェクトの作り方
- 依存パッケージのインストール方法
- 定番ライブラリ
- interface, ポインタ型の特徴
- sliceはimmutableでない、appendは破壊的

## 新規プロジェクトの作りかたがわからない

2019年現在では Go Modulesを使うのがデファクトだと思うので、それ前提であれば以下のようにプロジェクトを作成する。

```
$ PROJECT_NAME=myapp

$ mkdir -p path/to/${PROJECT_NAME}

$ cd $_

#
# Go Modulesプロジェクトとして初期化する
# これをやらない = go.modが無い状態だと、Go Modulesプロジェクトとして認識されない
#

$ go mod init github.com/${GITHUB_USER}/${PROJECT_NAME}
go: creating new go.mod: module github.com/${GITHUB_USER}/${PROJECT_NAME}

#
# 使う予定のパッケージをプロジェクトに追加する
#

$ go get github.com/hashicorp/hcl/v2@v2.2.0
go: finding github.com v2.2.0
go: finding github.com/hashicorp v2.2.0
go: finding github.com/hashicorp/hcl/v2 v2.2.0
go: finding github.com/hashicorp/hcl v2.2.0
go: downloading github.com/hashicorp/hcl/v2 v2.2.0
go: extracting github.com/hashicorp/hcl/v2 v2.2.0
go: downloading github.com/zclconf/go-cty v1.1.1
go: downloading github.com/agext/levenshtein v1.2.1
go: extracting github.com/agext/levenshtein v1.2.1
go: extracting github.com/zclconf/go-cty v1.1.1
go: finding github.com/zclconf/go-cty v1.1.1

$ cat go.mod
module github.com/${GITHUB_USER}/${PROJECT_NAME}

go 1.13

require github.com/hashicorp/hcl/v2 v2.2.0 // indirect
```

あとは [Using Makefile(s) for Go](https://danishpraka.sh/2019/12/07/using-makefiles-for-go.html) で紹介されているような Makefile を置いておくと便利です。

## 依存パッケージのインストール方法がわからない

ほぼGo Modules前提であると思われるGo 1.12以降の場合、`go get github.com/foobar` で依存パッケージを(go.modというファイルへ)追加するということと、`go.mod` に記載されている依存パッケージのうち足りないものは `go build`、`go run`時に自動的にインストールされる、ということを覚えておけば問題ないと思います。

なにかうまく行かない、という場合は以下の手順を参考に対応方法を決めてください。

---

まず、プロジェクトルート以下に`vendor/`ディレクトリが存在して、そこに依存先パッケージのソース一式が入ってるなら、改めてパッケージインストールする必要はない。`go run -mod=vendor`や`go test -mod=vendor` 実行してみて、パーケージ不足のエラーがでないならOK。

パッケージ不足のエラーが出たり、vendorがなかったりする場合は以下の手順で確認する。

* プロジェクトルートに`go.mod`というファイルがある場合はGo Moudlesという公式パッケージ管理ツールを使っているので、`go run` や `go build` 実行時に不足パッケージが自動的にダウンロードされるはず。あえて `vendor` を生成する必要がある場合は `go mod vendor` を実行する。
* プロジェクトルートに`Gopkg.toml`というファイルがある場合は、[dep](https://github.com/golang/dep)という以前の公式パッケージ管理ツールを使っているので、`dep ensure`を実行
* プロジェクトルートに`glide.yaml`というファイルがある場合は、`Glide`というパッケージ管理ツールを使っているので、`glide install`を実行
* プロジェクトルートに`Godeps`というディレクトリがある場合は`Godep`というパッケージ管理ツールを使ってるので、`godep get`を実行

## 依存ライブラリの一部だけforkしたものに置き換えたい場合はどうしたら?

`go.mod` 中で `replace` directive を使うと、 `=>` の左辺で指定したmoduleを右辺で指定したものに置き換えることができます。

`go.mod` 中の`import` をfork先に変更してしまうと、ソースコード中の `import` 元もfork先に変更しないといけなくなってしまうし、fork先のソースコードの`go.mod`中でのパッケージ名も変更しないといけないので、面倒ばかりなのでやらないほうがいいと思います。 `replace` しましょう。

例えば、 `github.com/google/go-github/v37` を `github.com/mumoshu/go-github` に fork して、色々変更を加えたソースのコミットに `v37.0.100` というタグをつけたとします。そのタグに `replace` するためには、以下のような `replace` を `go.mod` に追記します。

```go.mod
replace github.com/google/go-github/v37 => github.com/mumoshu/go-github/v37 v37.0.100
```

わざわざ `v37.0.100` のようなタグを打たなくてもコミットID等を指定できないんでしょうか？ 2021/08/01 現在 Go 1.16.x で試した限りでは、できないようです。

わざわざ fork しないで、ローカルディレクトリに向けることはできないんでしょうか？できます。

例えば、対象プロジェクトと同じレベルのディレクトリに go-github を git-clone して変更を加えている場合、以下のような `replace` でそのローカルディレクトリを参照させることもできます。 `../go-github` のところで現在のプロジェクトとの相対パスでいじった `go-github` を含むローカルディレクトリを指定しています。

```
replace github.com/google/go-github/v37 => github.com/mumoshu/go-github/v37 ../go-github
```

ただし、 `docker build` 中で `go build` するときに、 `replace` から参照したモジュールも build context に用意しておかないといけない点には注意してください。build context に導入できるのはカレントディレクトリ以下のファイルになるので、 `replace` で参照しているディレクトリもカレントディレクトリ以下において置く必要があります。

例えば、上記の `replace` が `go.mod` にある状態で以下のような Dockerfile を `docker build` すると落ちます。

```
COPY . .

RUN go build
```

`../go-github` ではなくカレントディレクト以下の、例えば `./go-github` に `replace` 先をおいておいて、 build context に含まれるようにしておけば問題ありません。

```
replace github.com/google/go-github/v37 => github.com/mumoshu/go-github/v37 ./go-github
```

Also see: https://stackoverflow.com/questions/53682247/how-to-point-go-module-dependency-in-go-mod-to-a-latest-commit-in-a-repo

## glide install成功したのに、依存先の依存先[^3]のパッケージが見つからない

[^3]: いわゆるTransitive Dependency

201６/03時点では、[自分で書いたコードから直接参照してる依存関係だけ解決するらしい](https://github.com/Masterminds/glide/issues/125)。それが、`glide.yaml`に直接書かれているパッケージだけが解決される、直接書かれていないものは解決されない、というのと同義なのかな・・・?

今まで経験したパッケージ管理ツールはtransitive dependencyを勝手に解決してくれるものばかりだったので、目からうろこでした。勝手に解決しないから、k8sみたいな大きなプロジェクトの一部だけを再利用しても、依存パッケージが爆発しなくて済む、ということなのかな?それは嬉しいですね。

## cliアプリ開発用のライブラリどれ使ったらいいんだろう

cli: https://github.com/codegangsta/cli
cobra: https://github.com/spf13/cobra

の2強っぽいけど、k8sとかCoreOS関係のOSSがcobra採用してるみたいなのでcobraにしました。
あと、cobraと同じ作者のviperと組み合わせると、コマンドラインフラグとYAMLファイルなどで設定をカスタマイズ可能なCLIが楽につくれます。

viper: https://github.com/spf13/viper

## Godepでパッケージ管理してるプロジェクトってどうやってビルドしたらいいの?

### go 1.5以降

godepは`vendor/`に対応している。プロジェクトのソースに`vendor/`ディレクトリが含まれているなら、godepにGOPATH以下を変更させなくてもビルドできるはず。(`vendor/`にすべての依存パッケージが`godep save`で保存されているはずなので)

`vendor/`が含まれるプロジェクトが`go build`でビルドできるように、godepで依存パッケージを管理しているプロジェクトは`godep go build`でビルドできるはず。

例えば、`export GOPATH=$HOME/Gopath`になっている場合、以下のようにする。

```
$ git clone git@github.com:kubernetes/contrib.git ~/Gopath/src/k8s.io/contrib
$ cd ~/Gopath/src/k8s.io/contrib/cluster-autoscaler/
$ make build
rm -f cluster-autoscaler
go get github.com/tools/godep
GOOS=linux godep go build ./...
GOOS=linux godep go build -o cluster-autoscaler
```

### go 1.5まで

godepはglideと違ってvendorを使わないので、プロジェクト毎にGOPATHを分けるほうが安全そう。ということで、GOPATHを作ってプロジェクトをそこにcloneし、次に`godep restore`によってGOPATH以下に依存パッケジージをダウンロードさせればビルドできる。

Glideを利用する前提のGOPATHと混ざらないように注意（まざっても実害はないと思うけど・・・不要なsrcがGopathに増えてしまって、きれいに掃除できなくなると思う)。

ホーム以下にそのプロジェクト専用のGOPATHを作るには、例えば以下のようにする。

```
$ export GOPATH=$HOME/Gopath-適当なID
$ mkdir -p $GOPATH/src/github.com/$ORG_OR_USER
$ git clone git@github.com:$ORG_OR_USER/$REPO.git $GOPATH/src/github.com/$ORG_OR_USER/$REPO
$ cd $GOPATH/src/github.com/$ORG_OR_USER/$REPO
$ godep restore
$ make hoge
```

プロジェクトルート以下にGOPATHをつくればよいのでは？と思うかもしれないが、godep的にNG。

```
$ mkdir -p path/to/project
$ git clone git@github.com:$ORG_OR_USER/$REPO.git path/to/project
$ cd path/to/project
$ export GOPATH=$(pwd)/go
$ godep restore
$ make bulid
...
godep: [WARNING]: godep should only be used inside a valid go package directory and
godep: [WARNING]: may not function correctly. You are probably outside of your $GOPATH.
godep: [WARNING]:      	Current Directory: /path/to/project
godep: [WARNING]:      	$GOPATH: /path/to/project/go
cluster_autoscaler.go:45:2: cannot find package "github.com/golang/glog" in any of:
```

## 「インタフェースのポインタ」は定義してはならない

　または、不要。

例えば、あるインタフェースInterfaceを実装するStructがあるとして、

```go
s Struct
i Interface
```

のとき

```go
s = i
```

は問題なく代入可能だが、

```go
s *Struct
i *Interface
```

のとき

```go
s = i
```

はコンパイルエラー。

インタフェースはポインタのようなもの(より正確には、インタフェースは型のポインタ+structへのポインタのようなもの)だから、ポインタのポインタへstructのポインタを代入するような意味合いになってしまう。

[go - Why can't I assign a *Struct to an *Interface? - Stack Overflow](http://stackoverflow.com/a/13511853)

## インタフェースはnilになれる＆Struct、Structへのポインタどちらも代入できる

https://play.golang.org/p/GpMgPexosL

```go
package main

import "fmt"

type Struct struct {}

type Interface interface {}

func main() {
	s1 := Struct{}
	s2 := &Struct{}

	var i1 Interface
	i1 = s1
	
	var i2 Interface
	i2 = s2

	fmt.Printf("%v, %v\n", i1, i2)
	//=> {}, &{}

	i1, i2 = nil, nil
	
	fmt.Printf("%v, %v\n", i1, i2)
	//=> <nil>, <nil>
}
```

## sliceはimmutableではない/appendは破壊的操作

appendはsliceを必ずしもコピーしない。言い換えると、appendするとappend先のsliceを変更してしまうこともある。具体的には、append先のsliceのサイズが足りなくなった場合に自動的にコピーされる（と思っているのですが、間違っていたら教えてください)。

あと、「sliceをコピー」と書いたが、この場合実際コピーされるのはslice(参照先配列のポインタ+長さ)の裏にある固定長配列といったほうが正しい気がする。

詳しくは以下

* [GoのSliceもヤバイ - Qiita](http://qiita.com/koher/items/3c570dfdd3ee25cd8017)を参照。
* [Go のスライスでハマッたところ - Block Rockin’ Codes](http://jxck.hatenablog.com/entry/golang-slice-internals2)

appendを使うときにお作法として

```go
a := append(a, "something")
```

のように再代入しているからといって、appendが必ずaをコピーしているかというと、そうではない。

[SliceTricks · golang/go Wiki](https://github.com/golang/go/wiki/SliceTricks)

# デプロイするまでに知りたかったこと

## バイナリサイズ大きくない?

- `go build -ldflags "-s -w"`を使う
- upx/goupxを使ってもいいけど、起動時間が伸びる

あわせて読みたい: [Shrink your Go binaries with this one weird trick](https://blog.filippo.io/shrink-your-go-binaries-with-this-one-weird-trick/)

## Dockerイメージのサイズ大きくない?

- 基本的にscratchイメージにGoバイナリをADDするだけにする
- scratchでだめなケースはalpineで賄えないか考える
    - CGO使うならビルド時に`apk add *dev`で必要devパッケージを入れて静的リンク。それをscratchイメージにADD
    - TLSでCA証明書が必要なら、scratchではなくalpineをベースにして、apk add ca-certificates

あわせて読みたい: [Dockerで最小のGoのイメージを作成する（cgo編） - Qiita](https://qiita.com/shibukawa/items/fe847e800f845c2f555d#step1-%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%86%E3%83%BC%E3%82%B8%E3%83%93%E3%83%AB%E3%83%89)

## 複数goバージョンを共存させたい

公式の「Installing extra Go versions」に書いてあるとおりだけど、`go get` で以前のバージョンのgoをインストールできる。例えば、1.12がある状態で1.11.11をインストールしたい場合は以下のようにする。

```
$ go get golang.org/dl/go1.11.11

$ go1.11.11
go1.11.11: not downloaded. Run 'go1.11.11 download' to install to /Users/myuser/sdk/go1.11.11

$ go1.11.11 download
Downloaded   0.0% (    16384 / 120494223 bytes) ...
Downloaded  32.6% ( 39239680 / 120494223 bytes) ...
Downloaded  76.3% ( 91979776 / 120494223 bytes) ...
Downloaded 100.0% (120494223 / 120494223 bytes)
Unpacking /Users/myuser/sdk/go1.11.11/go1.11.11.darwin-amd64.tar.gz ...
Success. You may now run 'go1.11.11'
```

これで `/Users/myuser/sdk/go1.11.11` 以下に 1.11.11 がインストールされ、`go1.11.11 <command>` でシステムのgoとは別バージョンのgoを直接利用できる。