5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

動かして覚えるGoのモジュールの使い方

Last updated at Posted at 2022-06-30

色々な記事見ていたんだけど難しく感じたり英語で書いてあって分かりにくかったので、具体的な説明は特になく、こんな感じに動くんだよ。と体感的に理解してもらいたく書きました。

自分としてもまだ知識不足なところあるから、もし間違っていたら教えてくれると嬉しいです。

今回は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メソッドを追加します。

module/module.go
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/go.mod
module exmaple.com/module

go 1.18

moduleディレクトリにgo.modが生成されます。

mainディレクトリでも同じように作ります。

main % go mod init example.com/main
main/go.mod
module example.com/main

go 1.18

こんな感じにmain.goにmodule/go.modのモジュール名をimportに書きます。

main/main.go
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文を追加します。

main/go.mod
module example.com/main

go 1.18

replace example.com/module => ../module

このようにreplaceの後に module/go.modのmodule名 => 実際のmoduleディレクトリの相対パス を書きます。
mainのディレクトリの中で

main % go mod tidy

と入力します。

main/go.mod
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
server/go.mod
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
)

server/go.sum
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に記述します。

server/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に追記します。

main/main.go
package main

import (
	//"example.com/module"         コメントアウト
	"example.com/server"           // 追加
	//"fmt"                        コメントアウト
)

func main() {
	//fmt.Println(module.Hello())  コメントアウト
	server.StartServer()           // 追加
}

main/go.mod
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
main/go.mod
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を勉強していて躓くポイントの一つだと思います。
今回は実際に動かしてみることで、言葉だけじゃ伝わりにくいところでも伝わるやすいのかなという想いで書きました。
なので、よかったらみなさん自身のパソコンで動かしてみてください。

こちら今回作ったソースコードですのでこちらでもよかったら確認してみてください。

参考にしたサイト

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?