Go Modulesも触れてみるGo入門
「Go言語ってどう?」と聞かれたり、Goで実装されたツールをカスタマイズする機会があったりしたのでGoに入門しました。
Goのプロジェクトで見かける GOPATH
, vendor
, Go Modules(vgo)について分かりづらかった🤔ので明らかにしながら、簡単なプロジェクトの始め方から入ろうと思います!
Goとは
2009年11月にGoogleから発表されたプログラミング言語で、ソースコードをコンパイルして実行するコンパイル型言語です。
シンプルさが求められて比較的簡単に学習できる言語です。
Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
https://golang.org/
有名な例だと、コンテナ型仮想環境を実現するDocker 本体が Goで実装されています🐳
また、パッケージというシステムがあり公式で用意されているパッケージでWebサーバを立てられるほか、GitHubなどからの外部パッケージを取得して便利な機能を使うことができます。
詳しくは他の記事に譲るとして、新しいGo Modulesでパッケージ取得を体験しながら入門しましょう。
Go Modulesとは
Go 1.11 から追加された外部パッケージの管理システムです。vgoと呼ばれることもあります。
プロジェクトを作るなどの作業を(後ほど説明する) GOPATH
の下でしなければならない制限が解消されます。
https://golang.org/doc/go1.11#modules
インストール
UNIXのターミナルが使えるときは anyenv と goenv
を導入しておきましょう。 RubyとかPythonとか他の言語も触るとき便利ですよ😃
anyenvを導入した場合は、次のように Go のインストールができます。
anyenv install goenv
exec $SHELL -l
goenv install -l
goenv install 1.12.5
goenv global 1.12.5
goenv rehash
GOPATH
は?
環境構築するときに GOPATH
を設定することがあります。 GOPATH
はデフォルトで ~/go/<バージョン>
になっていて、 Go Modulesを使う範囲では手で作らなくとも自動的に作成されます。
そして、このあとのGo Modulesで外部パッケージを取得するときに保存される場所でもあり、 ~/go/<バージョン>/pkg/mod
に保存されます。
また、 go install
で実行ファイルを配置する先が GOPATH/bin
になるため、PATHを通すことをおすすめします。
PATH=$PATH:$GOPATH/bin
(Go Modulesとは別のツールで)必要なパッケージを用意してくれる dep を使う場合、取得したファイルは GOPATH/pkg/dep
の下に配置されます。
ちなみに depを使うプロジェクトが GOPATH/src
の下にいないと次のエラーでパッケージを取得することができなくなります。
/path/to/go-project is not within a known GOPATH/src
vendor
を使っているプロジェクトもあるよ?
GitHub等でGoを用いたプロジェクトを見ると、 vendor
ディレクトリを使っているところがあります(ビルド方法や Makefile
に dep ensure
を用いているものがそうです)
- Go のプロジェクトに
vendor
があると、ビルド時 自動的にそれを使います - また、先程の
dep
ではdep ensure
を実行すると指定されたバージョンのパッケージをvendor
に配置しています
#初見でGitHubにあるGoのプロジェクトを改造したときに vendor
の挙動がわからなくてハマりました。
ただし、Go Modlues(vgo)が出た当初は GOPATH/src
や vendor
を廃止するようで、Go Modulesを使っているときはデフォルトで vendor
は無視されます。
要望もあるため 2019/06/13 現在も vendor
が使えるようになっています。Go Modulesの設定によって vendor
を使うようにすることもできます。
The initial series of vgo blog posts did propose dropping vendoring entirely, but feedback from the community resulted in retaining support for vendoring.
By default, go commands like go build ignore the vendor directory when in module mode.https://github.com/golang/go/wiki/Modules#how-do-i-use-vendoring-with-modules-is-vendoring-going-away
vgo v.s. dep
ちなみに、Goの外部パッケージ管理としてどのくらい使われているのか、どれくらい調べられているのか(Google トレンド での情報ですが)を見ると、まだまだ dep
のほうが強い印象があります。
Modulesを使う場合
はじめに、Goのプロジェクトとなるディレクトリを作成して、 go mod init
を実行します。
GOPATH/src
以下にディレクトリを作った状態で go mod init
を実行するとModulesが無効化されている旨のメッセージが出るため、 GOPATH
以外の場所にディレクトリを作りましょう。
go: modules disabled inside GOPATH/src by GO111MODULE=auto; see ‘go help modules’
mkdir go-project
go mod init go-project
go mod init
のあとにプロジェクト名を指定しないと次のエラーが出ます。
go: cannot determine module path for source directory /path/to/go-project (outside GOPATH, no import comments)
実行したあとは go.mod
のファイルが作成されています。
$ ls
go.mod
次に、 main.go
のファイルを作り、外部パッケージを体験するために次のコードを使います。
https://github.com/hackebrot/turtle の README.md
とほぼ同じです。
vi main.go
package main
import (
"fmt"
"os"
"github.com/hackebrot/turtle"
)
func main() {
name := "wolf"
emoji, ok := turtle.Emojis[name]
if !ok {
fmt.Fprintf(os.Stderr, "no emoji found for name: %v\n", name)
os.Exit(1)
}
fmt.Printf("Name: %q\n", emoji.Name)
fmt.Printf("Char: %s\n", emoji.Char)
fmt.Printf("Category: %q\n", emoji.Category)
fmt.Printf("Keywords: %q\n", emoji.Keywords)
}
最後に、ソースコードをビルドして実行しましょう。
出来上がった実行ファイルは go mod init
で指定したプロジェクト名になります
(example.com/sample
のように作った場合は実行ファイルの名前が sample
になります)
go build
./go-project
たったこれだけです😁内容は実行してのお楽しみに
これまでのように dep を導入して GOPATH
を設定して…をせずともModulesを有効にした状態で go build
をすると外部パッケージを自動で取得してビルドまで進めてくれます。
Modulesを使った場合の外部パッケージのバージョン管理
ちなみにパッケージのバージョンは go.mod
で管理されています 😁
$ cat go.mod
module go-project
go 1.12
require (
github.com/google/go-cmp v0.3.0 // indirect
github.com/hackebrot/go-repr v0.0.0-20170331152400-586d894a5734 // indirect
github.com/hackebrot/turtle v0.1.0
)
Modulesを使わず go get
する場合
Go Modulesを使わない場合も見てみましょう。
まず、プロジェクトを作成するのですが、GOPATH/src
以下のディレクトリはGo Modulesが無効化されることを利用して GOPATH/src/
にプロジェクトを作りましょう。
$ pwd
/path/to/gopath/
$ mkdir -p src/example.com/go-project
$ cd src/example.com/go-project
$ pwd
/path/to/gopath/src/example.com/go-project
続いて、 go get
で必要なパッケージを取得します。
go get "github.com/hackebrot/turtle"
「Modulesを使う場合」と同様に main.go
を作って、実行しましょう。 ソースコードの内容は同じです。
vi main.go
go build
./go-project
go get
で外部パッケージを取得した場合
さて、Modulesを使った場合と、go get
を使った場合は何が違うのでしょうか。
Modulesの場合、 go get
を使わずにパッケージを取得できる利点は説明しました。
さらに、ビルド後のプロジェクト内や go get
で取得したパッケージの場所をみると、パッケージのバージョンを表すものが何もありません。
$ ls
main.go sample
$ ls $GOPATH/src/github.com/hackebrot/turtle
CONTRIBUTORS.md README.md doc.go examples_test.go filters_test.go turtle_test.go
LICENSE cmd emojis.go filters.go turtle.go
このように、 go get
で外部パッケージを取得すると パッケージのバージョンが管理されず、最新の状態でパッケージがダウンロードされます。
プロジェクトごとに外部パッケージのバージョンを決めたいときや、複数人でプロジェクトを共有してバージョンを揃えたいときに不便になります。
Go Modulesが登場する前は dep などでパッケージのバージョン管理をしていました。これからは公式で、Goを導入した瞬間にこのパッケージのバージョン管理ができるのです。
次のステップとしては
簡単ではありますが、Go Modulesの使い方を把握してGoプロジェクトの始め方をつかめたはずです。次の記事を参考にしてGoでできることを増やしましょう。
A Tour of Go(日本語版)
文法を覚えるには A Tour of Go で 実際に入力しながら 進めるのをおすすめします。ディレクトリを用意せずともGoの文法に触れられます。
流し読みしたらfor文を書くところで一瞬「あれ?」となりました
ただし「ニュートン法による平方根の求め方」などとっつきにくい部分があります。
#ニュートン法のところで何をしていいか分からなければ、とりあえず10回ループさせて2の平方根を求めてみてください😀
A Tour of Go(日本語版)
https://go-tour-jp.appspot.com/welcome/1
Go言語の初心者が見ると幸せになれる場所 #golang
そのほかに、Goを始めるときや、より良いコードを書くために必要なことがまとまっている次の記事が参考になります。
Go言語の初心者が見ると幸せになれる場所 #golang
https://qiita.com/tenntenn/items/0e33a4959250d1a55045
Go言語の基礎〜Go 1.11 開発環境構築とパッケージバージョン管理〜
また、 この記事ではGo Modulesについてさわりしかやっていないので、もう少しModulesのコマンドに触れてみたいと感じたならこちらも参考になります。
Go言語の基礎〜Go 1.11 開発環境構築とパッケージバージョン管理〜
Awesome Go : 素晴らしい Go のフレームワーク・ライブラリ・ソフトウェアの数々
サンプルを作るにあたり、Goの外部パッケージを探すにはこちらが参考になりました。
Awesome Go : 素晴らしい Go のフレームワーク・ライブラリ・ソフトウェアの数々
https://qiita.com/hatai/items/f31914f37dc6c53b2bce
あとがき
Go Modulesの場合は GOPATH
を設定しなくても動作します。
しかし、現在でもパッケージ管理にGo Modulesではなくdepが使われているように見え、depを使う場合は GOPATH
を用意しないと正しく動作しません。
また、GOPATHについて調べていくと、Goでプロジェクトを作って開発し始めるには github.com/user/repository のような形でGOPATHに…という情報もあり、混乱しがちでした 😵
本記事のようにGitHubのリポジトリを意識しない形式でもプロジェクトは始められますが、GitHubを意識したプロジェクト構成で、名前は go-sample
でもいいので学習結果をGitHubに残したほうが良いかもしれませんね😉
The Go Gopher by Renee French CC BY 3.0