go.modのreplaceでローカルにある別プロジェクトにアクセスする

2022/03/05に公開

go.modはgithub等外部にあるパッケージをプロジェクトに追加することができます。
外部ではなく、ローカルにある別プロジェクトにもアクセスできるか調べました。

ディレクトリ構成

.
├── project1
│   ├── aaa.go
│   ├── go.mod
│   └── iii
│       └── iii.go
└── project2
    ├── go.mod
    └── main.go

project2のmain.goからproject1のaaa.goとiii/iii.goにアクセスします。
簡単なproject1の中身から見ていきます。

project1

go.mod

module project1

go 1.17

go mod init project1
を実行すると作成されるgo.modです。
go.modが無いとproject2にgoのプロジェクトとして認識されないので作成しました。

aaa.go

package aaa

import "fmt"

func ShowText() {
	fmt.Println("project1/aaa.goです。")
}

packageはaaaです。
publicメソッドの必要があるのでShowTextメソッドの先頭文字(S)は大文字にして下さい。

iii/iii.go

package iii

import "fmt"

func ShowText() {
	fmt.Println("project1/iii/iii.goです。")
}

packageはiiiです。
iii.goを配置するディレクトリ名をパッケージ名と合わせました。

project2

go.mod

module project2

go 1.17

require project1 v0.0.0

replace project1 => ../project1

project2のgo.modです。

require

go buildを実行した時にパッケージが無く自動取得、またはgo getで指定したパッケージを取得した時に、パッケージ情報がrequire部分に記述されます。
今回はローカルにあるプロジェクトにアクセスしたいので任意の名前とバージョンを手入力します。
require [任意のパッケージ名] v[x.x.x]

replace

外部パッケージに対しては、バージョンを置き換えるのに使うことが多いようです。
今回はreplaceを使って、先ほどrequireで作成したproject1パッケージにPathを指定します。
replace [パッケージ名] => [ローカルプロジェクトのPath]

main.go

package main

import (
	"fmt"
	aaa "project1"
	"project1/iii"
)

func main() {
	fmt.Println("project2のmainです。")
	aaa.ShowText()
	iii.ShowText()
}

先ほどgo.modのrequireで作成したproject1をimportで使います。
project1/iii/iii.goのほうはディレクトリ名(iii)とパッケージ名(iii)が一致しているため、パッケージ名.メソッド()という形でメソッドにアクセスできます。
project1/aaa.goのようにディレクトリ名(project1)とパッケージ名(aaa)が不一致の場合は、エイリアスをパッケージ名の左側にエイリアスを記述する必要があります。

やってみる

project2ディレクトリに移動し実行します。

project2 % go run main.go
project2のmainです。
project1/aaa.goです。
project1/iii/iii.goです。

project2のmain.goからproject1の格パッケージへアクセスすることができました。
モジュールの管理や各ファイルへのアクセス方法についてはまだまだ分からないことばかりなので少しずつ調査を進めていこうと思います。

internal package

golangには外部プロジェクトからのアクセスを許可したくないファイルを守るinternal packageという機能があります。
internalという名前のディレクトリにファイルを配置するだけで良いそうです。

.
├── project1
│   ├── aaa.go
│   ├── go.mod
│   ├── iii
│   │   └── iii.go
│   └── internal
│       └── uuu.go
└── project2
    ├── go.mod
    └── main.go
package main

import (
	"fmt"
	aaa "project1"
	"project1/iii"
	uuu "project1/internal"
)

func main() {
	fmt.Println("project2のmainです。")
	aaa.ShowText()
	iii.ShowText()
	uuu.ShowText()
}

internalディレクトリにuuuというパッケージのファイルを作成しました。
実行してみます。

% go run main.go
package command-line-arguments
        main.go:7:2: use of internal package project1/internal not allowed

internal packageにより、project1/internalへのアクセスは拒絶されました。

参考

https://qiita.com/hnishi/items/a9217249d7832ed2c035
https://text.baldanders.info/golang/internal-packages/
https://qiita.com/taji-taji/items/5a4f17bcf5b819954cc1

Discussion