色々な記事見ていたんだけど難しく感じたり英語で書いてあって分かりにくかったので、具体的な説明は特になく、こんな感じに動くんだよ。と体感的に理解してもらいたく書きました。
自分としてもまだ知識不足なところあるから、もし間違っていたら教えてくれると嬉しいです。
今回は1.18から追加されたworkspaceモードではなく、今までのモジュール管理をどうやっていたか動かしながら説明していきます。
workspaceモードはこちらから試せます!↓
動かして覚えるGoのWorkspaceモードの使い方
実行環境
- M1 Macbook Air
- macOS Monterey 12.4
- Go 1.18
WindowsでもGoがちゃんとインストールされていれば大丈夫です。
使い方
例えば、このようなディレクトリ構造があります。
% tree
.
├── main
│ └── main.go
└── module
└── module.go
module.goにHelloメソッドを追加します。
package module
func Hello() string {
h := "hello"
return h
}
mainモジュールでmoduleのHelloメソッドを使いたい場合、
moduleディレクトリ内で「go mod init」を実行します。
module % go mod init example.com/module
↑「example.com」のところは、aaaa.bbbというようなドットを含む形で書けば好きな文字で良いみたいです。
(ユニーク(誰とも被らない)な文字の方が良いみたい。)
(よく見るのはgithub.com/自分のアカウント名/プロジェクト名/moduleとか)
module exmaple.com/module
go 1.18
moduleディレクトリにgo.modが生成されます。
mainディレクトリでも同じように作ります。
main % go mod init example.com/main
module example.com/main
go 1.18
こんな感じにmain.goにmodule/go.modのモジュール名をimportに書きます。
package main
import (
"fmt"
"example.com/module"
)
func main() {
fmt.Println(module.Hello())
}
この状態で一度動かしてみます。
mainディレクトリに移動して
main % go run main.go
main.go:4:2: module example.com/module provides package example.com/module and is replaced but not required; to add it:
go get example.com/module
動きませんでした。
Google翻訳曰く、「モジュールexample.com/moduleはパッケージexample.com/moduleを提供し、置き換えられますが必須ではありません。 追加するには:go get example.com/module」
と書かれています。
じゃあ言われた通り入力してみましょう。
main % go get example.com/module
go get: unrecognized import path "example.com/nodule": reading https://example.com/nodule?go-get=1: 404 Not Found
Google翻訳曰く、「認識されないインポートパス"example.com/nodule":読み取りhttps://example.com/nodule?go-get=1:404 Not Found」
こんな感じにまた怒られてしまいました。
多分これはローカルで作ったものなのでURLがないよ!って怒られているんだと思います。
解決方法
main/go.modにreplace文を追加します。
module example.com/main
go 1.18
replace example.com/module => ../module
このようにreplaceの後に module/go.modのmodule名 => 実際のmoduleディレクトリの相対パス を書きます。
mainのディレクトリの中で
main % go mod tidy
と入力します。
module example.com/main
go 1.18
replace example.com/module => ../module
require example.com/module v0.0.0-00010101000000-000000000000
すると、main/go.modにrequire文追加されます。
こうすることで、自分のモジュールを別のモジュールから利用できるようになります。
main % go run main.go
hello
このような感じでHelloメソッドが使えました。
最終的なディレクトリ構造はこのようになっています。
.
├── main
│ ├── go.mod
│ └── main.go
└── module
├── go.mod
└── module.go
外部パッケージをmoduleにimportして使う方法
次は、外部パッケージとしてechoをserverディレクトリにインポートしてmainディレクトリでサーバーを起動してみます。
まずserverディレクトリを用意します。
ディレクトリ構造はこんな感じ
├── main
│ ├── go.mod
│ └── main.go
├── module
│ ├── go.mod
│ └── module.go
└── server
└── server.go
serverディレクトリに移動して
server % go mod init example.com/server
go.modファイルを作成します。
ここのInstallationの「go get github.com/labstack/echo/v4」をserverディレクトリで打ちます。
server % go get github.com/labstack/echo/v4
go: downloading github.com/labstack/echo v1.4.4
go get: added github.com/labstack/echo/v4 v4.7.2
module example.com/server
go 1.18
require (
github.com/labstack/echo/v4 v4.7.2 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/text v0.3.7 // indirect
)
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI=
github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
こんな感じにインストールされたらOK。
server.goに記述します。
package server
import (
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"net/http"
)
func StartServer() {
// Echo instance
e := echo.New()
// Middleware
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Routes
e.GET("/", hello)
// Start server
e.Logger.Fatal(e.Start(":1234"))
}
// Handler
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello World!")
}
mainディレクトリに移動して、main.goとgo.modに追記します。
package main
import (
//"example.com/module" コメントアウト
"example.com/server" // 追加
//"fmt" コメントアウト
)
func main() {
//fmt.Println(module.Hello()) コメントアウト
server.StartServer() // 追加
}
module example.com/main
go 1.18
replace (
example.com/module => ../module
example.com/server => ../server // 追加
)
require example.com/module v0.0.0-00010101000000-000000000000
複数replaceを書く時は、()で囲んで書くことができる。
書き終わったら、mainディレクトリで「go mod tidy」を入力する
% go mod tidy
module example.com/main
go 1.18
replace (
example.com/module => ../module
example.com/server => ../server // 追加
)
// example.com/moduleコメントアウトして使用されていないので削除された
// 新しく使用しているexample.com/serverが追加された!
require example.com/server v0.0.0-00010101000000-000000000000
require (
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/labstack/echo/v4 v4.7.2 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
)
このように追加されていたらOK。
ではサーバーを起動してみましょう。
main % go run main.go
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.7.2
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
⇨ http server started on [::]:1234
この状態で、http://localhost:1234/
こちらに移動すると、Hello World!と表示されているはずです。
最終的にはこのようなディレクトリ構造になっているかと思います。
.
├── main
│ ├── go.mod
│ ├── go.sum
│ └── main.go
├── module
│ ├── go.mod
│ └── module.go
└── server
├── go.mod
├── go.sum
└── server.go
まとめ
このモジュール管理はGoを勉強していて躓くポイントの一つだと思います。
今回は実際に動かしてみることで、言葉だけじゃ伝わりにくいところでも伝わるやすいのかなという想いで書きました。
なので、よかったらみなさん自身のパソコンで動かしてみてください。
こちら今回作ったソースコードですのでこちらでもよかったら確認してみてください。
参考にしたサイト