パッケージについて

完了

Go のパッケージは、他のプログラミング言語のライブラリやモジュールのようなものです。 コードをパッケージ化すれば、別の場所で再利用できます。 パッケージのソース コードは、複数の .go ファイルで配布できます。 これまでは、main パッケージを記述し、他のネイティブ パッケージをいくつか参照してきました。

このセクションでは、パッケージとは何かについて学びます。 その作成方法と外部パッケージの使用方法についても学びます。

メイン パッケージ

ご存知かもしれませんが、どんなに単純な Go のプログラムでもパッケージの一部でなければなりません。 通常、既定のパッケージは main パッケージであり、これは今までに扱ってきたものです。 プログラムが main パッケージの一部である場合、Go によってバイナリ ファイルが生成されます。 このファイルを実行すると、main() 関数が呼び出されます。

言い換えれば、main パッケージを使用するときは、プログラムによってスタンドアロンの実行可能ファイルが生成されます。 しかし、プログラムが main 以外のパッケージの一部である場合、Go はバイナリ ファイルを生成しません。 パッケージ アーカイブ ファイル (.a 拡張子のファイル) が生成されます。

Go では、パッケージ名には規則があります。 パッケージでは、そのインポート パスの最後の部分が名前として使用されます。 たとえば、Go の標準ライブラリには、複雑な数値を操作する便利なコードがある math/cmplx というパッケージが含まれています。 このパッケージのインポート パスは math/cmplx で、これは次のようにインポートします。

import "math/cmplx"

このパッケージ内のオブジェクトを参照するには、cmplx のようにパッケージ名を使用します。

cmplx.Inf()

パッケージを作成してみましょう。

パッケージを作成する

$GOPATH/src 内に calculator という名前で新しいディレクトリを作成します。 sum.goという名前でファイルを作成します。 ツリー ディレクトリは次のディレクトリのようになります。

src/
  calculator/
    sum.go

パッケージの名前で sum.go ファイルを初期化します。

package calculator

パッケージの関数と変数を記述する準備ができました。 他のプログラミング言語と違って、Go には、変数または関数をパッケージの外または中のどちらから呼び出せるのかを示す public または private キーワードは用意されていません。 しかし、Go では 2 つの簡単な規則に従います。

  • プライベートにする要素は、名前の先頭を小文字にします。
  • パブリックにする要素は、名前の先頭を大文字にします。

それでは、作成中の calculator パッケージに次のコードを追加してみましょう。

package calculator

var logMessage = "[LOG]"

// Version of the calculator
var Version = "1.0"

func internalSum(number int) int {
    return number - 1
}

// Sum two integer numbers
func Sum(number1, number2 int) int {
    return number1 + number2
}

コード内のいくつかの点に注目してください。

  • logMessage 変数はパッケージの中からしか呼び出せません。
  • Version 変数はどこからでもアクセスできます。 この変数の目的を説明したコメントを含めることをお勧めします。 (この説明はパッケージを使用するすべての人に役立ちます。)
  • internalSum 関数はパッケージの中からしか呼び出せません。
  • Sum 関数はどこからでもアクセスできます。 関数の目的を説明したコメントを含めることをお勧めします。

calculator ディレクトリで go build コマンドを実行して、何も問題がないことを確認します。 実行しても、実行可能バイナリは生成されないことに注意してください。

モジュールを作成する

パッケージに電卓機能を配置できました。 今度は、パッケージをモジュールに入れます。 Go のモジュールには、関連機能を提供するパッケージが通常含まれています。 パッケージのモジュールには、グループ化したコードを実行するために Go が必要なコンテキストも指定されています。 このコンテキスト情報には、コードを記述した対象の Go のバージョンが含まれます。

また、モジュールにより、他の開発者がコードの特定のバージョンを参照しやすくなり、依存関係の管理が容易になります。 もう 1 つの利点は、プログラムのソース コードが厳密に $GOPATH/src ディレクトリに存在する必要がないことです。 この制限から解放されることで、さまざまなパッケージ バージョンを他のプロジェクトで同時に、より便利に扱えるようになります。

さて、calculator パッケージのモジュールを作成するには、ルート ディレクトリ ($GOPATH/src/calculator) で次のコマンドを実行します。

go mod init github.com/myuser/calculator

このコマンドを実行すると、github.com/myuser/calculator がモジュール名になります。 他のプログラムで参照するには、この名前を使用します。 このコマンドにより、go.mod という名前の新しいファイルも作成します。 最後に、ツリー ディレクトリは次のディレクトリのようになります。

src/
  calculator/
    go.mod
    sum.go

go.mod ファイルの内容は次のコードのようになります。 (Go バージョンは異なっている可能性があります。)

module github.com/myuser/calculator

go 1.14

他のプログラムでご自分の calculator パッケージを参照するには、そのモジュール名を使用してインポートします。 この場合、名前は github.com/myuser/calculator です。 では、このパッケージの使用方法の例を見てみましょう。

Note

歴史的に、Go での依存関係の管理は簡単ではありませんでした。 依存関係管理システムはまだ発展途上です。 モジュールについてさらに理解を深めるには、こちらの Go ブログで公開中の一連の記事をご覧ください。

ローカル パッケージ (モジュール) の参照

それでは、パッケージを使ってみましょう。 これまで扱ってきたサンプル アプリケーションの続きです。 今回は、sum 関数を main パッケージに入れるのではなく、前に calculator パッケージに作成したものを使ってみましょう。

ツリー ファイルの構造は次のようになります。

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    main.go

$GOPATH/src/helloworld/main.go ファイルには次のコードを使用します。

package main

import (
  "fmt"
  "github.com/myuser/calculator"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
}

作成済みパッケージの名前 (calculator) を import ステートメントで使用していることに注意してください。 そのパッケージから Sum 関数を呼び出すには、パッケージ名を calculator.Sum のように含める必要があります。 最終的に、Version 変数にもアクセスできるようになりました。 calculator.Version のように呼び出します。

ここでプログラムを実行しようとしても、動作しません。 モジュールを使用して他のパッケージを参照することを Go に知らせる必要があります。 これを行うには、$GOPATH/src/helloworld ディレクトリで次のコマンドを実行します。

go mod init helloworld

前のコマンドでは、helloworld はプロジェクトの名前です。 このコマンドにより新しい go.mod ファイルが作成され、ツリー ディレクトリは次のようになります。

src/
  calculator/
    go.mod
    sum.go
  helloworld/
    go.mod
    main.go

go.mod ファイルを開くと、次のコードのような内容があります。 (Go バージョンは異なっている可能性があります。)

module helloworld

go 1.14

モジュールのローカル コピーを参照しているので、リモートの場所を使用しないことを Go に知らせる必要があります。 そのため、次のように、go.mod ファイルを手動で修正して参照を含める必要があります。

module helloworld

go 1.14

require github.com/myuser/calculator v0.0.0

replace github.com/myuser/calculator => ../calculator

replace キーワードでは、モジュールのリモートの場所ではなくローカル ディレクトリを使用するように指定します。 この場合、helloworld および calculator プログラムは $GOPATH/src にあるため、場所は単に ../calculator となっています。 モジュールのソースが別の場所にある場合は、ここでローカル パスを定義します。

次のコマンドを使用してプログラムを実行します。

go run main.go

出力は次のようになります。

8
Version:  1.0

課題 1

main アプリケーションで calculator パッケージの logMessage 変数または internalSum 関数を呼び出そうとするとどうなるでしょうか。 実行されるでしょうか。 試してみる

課題のソリューション:

package main

import (
 "fmt"
 "github.com/myuser/calculator"
)

func main() {
    total := calculator.internalSum(5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.logMessage)
}

パッケージの公開

Go パッケージの公開はごく簡単です。 必要なのは、パッケージのソース コードを公開することだけです。 ほとんどの開発者は GitHub を使用して、パッケージを一般公開します。そのため、import ステートメントで github.com への参照が見つかる場合があります。

たとえば、calculator パッケージを GitHub アカウントに公開する場合、calculator という名前のリポジトリを作成する必要があります。 URL は次のようになります。

https://github.com/myuser/calculator

次のように、リポジトリにタグを付けてパッケージのバージョンを指定します。

git tag v0.1.0
git push origin v0.1.0

(自分も含め) このパッケージを使用する開発者は、次のようにして参照します。

import "github.com/myuser/calculator"

サードパーティのパッケージを参照する方法について、もう少し詳しく説明します。

外部 (サードパーティ) パッケージを参照する

プログラムで、他の開発者が記述したパッケージを参照することが必要な場合があります。 通常、これらのパッケージは GitHub にあります。 パッケージ (main 以外のパッケージ) とスタンドアロン プログラム (main パッケージ) のどちらを開発している場合でも、次の手順でサードパーティのパッケージを参照できます。

rsc.io/quote パッケージへの参照を追加してみましょう。

package main

import (
    "fmt"
    "github.com/myuser/calculator"
    "rsc.io/quote"
)

func main() {
    total := calculator.Sum(3, 5)
    fmt.Println(total)
    fmt.Println("Version: ", calculator.Version)
    fmt.Println(quote.Hello())
}

Visual Studio Code を使用している場合、go.mod ファイルはファイルの保存時に更新されます。 次のように表示されます。

module helloworld

go 1.14

require (
    github.com/myuser/calculator v0.0.0
    rsc.io/quote v1.5.2
)

replace github.com/myuser/calculator => ../calculator

rsc.io/quote でパッケージの特定のバージョンを参照する方法に注目してください。 プログラムの依存関係をアップグレードする必要がある場合は、ここでバージョンを変更する必要があります。

次のコマンドを使用してプログラムを再実行します。

go run main.go

出力は次のようになります。

8
Version:  1.0
Hello, world.

サードパーティ パッケージへの将来の参照はすべて、go.mod ファイルに含まれている必要があります。 アプリケーションを実行またはコンパイルすると、その依存関係のすべてが Go によってダウンロードされます。