はじめに
前のセクションでは、次のコード行を含む基本的な Go プログラムを作成しました。
package main
import "fmt"
これらの 2 行のコードをどのように理解すればよいでしょうか。また、packageとimport文を効果的に使うにはどうすればよいでしょうか。
この実験では、Go でパッケージを作成してインポートする方法を学びます。これにより、コードを再利用可能なモジュールに整理して、Go プロジェクトをより保守しやすく拡張可能にすることができます。
ポイント
- パッケージの定義と宣言
- エクスポートされた(公開)識別子とエクスポートされていない(非公開)識別子の理解
- パッケージのインポートのさまざまな形式:単一、グループ化、ドット、エイリアス、および匿名インポート
パッケージの宣言と定義
Go におけるパッケージは、Python のモジュールや C のライブラリに似ています。コードを整理して再利用するために使用されるソースコードファイルのコレクションです。すべての Go ファイルは、ファイルの先頭でパッケージを宣言する必要があります。
注: Go プログラムは、実行のエントリポイントとして機能する
mainという名前の 1 つだけのパッケージを持たなければなりません。それがなければ、プログラムは実行可能ファイルを生成できません。
ポイント
- エクスポートされた(公開)識別子:大文字で始まる識別子(変数、関数、型など)は、他のパッケージからアクセスできます。これらは、パッケージの公開インターフェイスと考えられます。
- エクスポートされていない(非公開)識別子:小文字で始まる識別子は、同じパッケージ内でのみアクセスできます。これらは、パッケージの内部実装の詳細と考えられます。
- パッケージの凝集性:同じフォルダ内のすべてのファイルは、同じパッケージに属する必要があります。これにより、関連するコードがまとまったままになります。
- パッケージの命名規則:パッケージ名は、小文字で、短く、説明的で、アンダースコアや大文字を避ける必要があります。
独自のカスタムパッケージを作成しましょう。
propagandistという名前のフォルダを作成し、その中にpropagandist.goというファイルを作成します。mkdir ~/project/propagandist touch ~/project/propagandist/propagandist.gopropagandist.goに次のコードを記述します。package propagandist var Shout = "I Love LabEx" // 公開変数 var secret = "I love the dress" // 非公開変数 func Hit() string { return "Don't hit me, please!" }Shoutは公開で、大文字で始まるため、propagandistをインポートする他のパッケージからアクセスできます。secretは非公開で、小文字で始まるため、propagandistパッケージ内でのみ使用できます。Hitは公開関数で、他のパッケージからアクセスできます。
パッケージ用の Go モジュールを初期化します。
cd ~/project/propagandist go mod init propagandistこのコマンドは、
propagandistディレクトリに新しい Go モジュールを初期化し、パッケージの依存関係を管理するのに役立ちます。
単項目インポート
propagandistパッケージを使用するには、新しい Go プログラムを作成しましょう。この手順では、Go コードで単一のパッケージをインポートして使用する方法を示します。
プロジェクトフォルダに新しい Go ファイル
pacExercise.goを作成します。touch ~/project/pacExercise.goプログラム用の Go モジュールを初期化します。
cd ~/project go mod init pacExercisego.modファイルを更新して、ローカルパッケージの依存関係を追加します。ターミナルで次のコマンドを実行します。echo "replace propagandist =>./propagandist" >> go.mod重要: このコマンドは、
go.modファイルにreplaceディレクティブを追加します。これは重要です。なぜなら、これにより Go に対して、propagandistパッケージをリモートリポジトリからダウンロードしようとせずに、ローカルディレクトリ./propagandistからソースを取得するように指示するからです。このコマンドをターミナルで実行すると、go.modファイルにreplace propagandist =>./propagandistの行が追加されます。直接この行をファイルに手動で書き込まないでください。pacExercise.goに次のコードを書いて、propagandistパッケージをインポートして使用します。package main import ( "fmt" "propagandist" ) func main() { fmt.Println(propagandist.Shout) // 公開変数にアクセス }- このコードは、出力を表示するための
fmtパッケージとpropagandistパッケージをインポートします。 - その後、
propagandist.Shoutを使用してpropagandistパッケージから公開変数Shoutにアクセスします。
- このコードは、出力を表示するための
プログラムを実行します。
go mod tidy go run pacExercise.gogo mod tidyコマンドは、新しい依存関係でgo.modファイルを更新することを確認します。go run pacExercise.goコマンドは、プログラムをコンパイルして実行します。予想される出力:
I Love LabEx
グループ化されたインポート
複数のパッケージをインポートする際には、読みやすさと整理のためにグループ化されたインポートを使用できます。これはスタイルに関する選択事項であり、コードの機能には影響しません。
pacExercise.goを変更して、グループ化されたインポートを使用します。package main import ( "fmt" "propagandist" ) func main() { fmt.Println(propagandist.Shout) }上のコードスニペットでは、
fmtとpropagandistの各パッケージが、丸括弧で囲まれた単一のimportブロック内にインポートされています。これにより、複数のパッケージのインポートを読みやすく管理しやすくなります。これは、前の例とまったく同じであり、グループ化されたインポート構文の使い方を示しています。プログラムを実行して、依然として機能することを確認します。
go run pacExercise.goプログラムはエラーなく実行され、以前と同じ結果が出力されるはずです。
ドットインポート
ドットインポートを使用すると、関数や変数を呼び出す際にパッケージ名の接頭辞を省略できます。名前空間の競合を引き起こし、読みやすさを低下させる可能性があるため、明示的なパッケージ名を推奨することが多いです。ただし、それが何であるかを知っておくのは良いでしょう。
pacExercise.goを変更して、fmtに対してドットインポートを使用します。package main import. "fmt" import "propagandist" func main() { Println(propagandist.Shout) // `fmt.` 接頭辞は不要 }
- ここで、
import. "fmt"は、fmtパッケージの関数や変数をfmt.接頭辞なしで直接使用できることを意味します。 - たとえば、
fmt.Printlnの代わりにPrintlnを使用します。
プログラムを実行します。
go run pacExercise.go予想される出力:
I Love LabEx
エイリアスインポート
2 つのパッケージが似た名前を持っている場合、明確さを保つためまたは競合を回避するために、インポートされたパッケージにエイリアスを付けることができます。これは、コードの読みやすさを向上させ、名前空間の衝突を管理するのに役立ちます。
pacExercise.goを変更して、fmtをioとしてエイリアス付けします。package main import io "fmt" import "propagandist" func main() { io.Println(propagandist.Shout) // `fmt`の代わりにエイリアス`io`を使用 }import io "fmt"は、fmtパッケージに対してエイリアスioを作成します。- これで、
fmt.Printlnの代わりにio.Printlnを使用します。
プログラムを実行します。
go run pacExercise.go
匿名インポート
匿名インポートは、副作用のためにパッケージをインポートするために使用されます。たとえば、そのinit()関数を実行するために、そのエクスポートされた識別子のいずれかを直接参照する必要がない場合です。これは、ドライバを登録するパッケージやその他の初期化タスクを実行するパッケージに役立ちます。
pacExercise.goを変更して、timeの匿名インポートを含めます。package main import ( "fmt" "propagandist" _ "time" // 匿名インポート ) func main() { fmt.Println(propagandist.Shout) }import _ "time"は匿名インポートです。アンダースコア_はブランク識別子として使用され、コンパイラに対して、副作用のためにパッケージをインポートしており、コード内でそれから直接何も参照しないことを伝えます。- このプログラムが実行されるとき、
timeパッケージのinit()関数が実行されます。ここではtimeパッケージには特に目に見える副作用はありませんが、多くのパッケージではこれを使用してデータベースドライバや構成設定を登録しています。
プログラムを実行します。
go run pacExercise.go予想される出力:
I Love LabEx
まとめ
この実験では、以下のことを学びました。
- Go 言語でカスタムパッケージを作成して定義し、再利用可能なコードをカプセル化する方法
- 公開(エクスポート)された識別子と非公開(エクスポートされていない)識別子の違いと、それがアクセシビリティに与える影響
- パッケージをインポートするさまざまな方法とそのそれぞれの使用例
- 単項目インポート:1 回に 1 つのパッケージをインポートする
- グループ化されたインポート:整理をよくするために 1 つのブロックで複数のパッケージをインポートする
- ドットインポート:パッケージ名の接頭辞なしで直接その識別子を使用してパッケージをインポートする(注意して使用)
- エイリアスインポート:読みやすさを向上させるか、または名前の競合を回避するためにインポートされたパッケージを改名する
- 匿名インポート:初期化などの副作用のためだけにパッケージをインポートする
- パッケージ内の
init()関数の役割と、匿名インポートがその実行をトリガーする方法
この実験を完了することで、パッケージを使って Go プロジェクトを効果的に構造化して管理できるようになりました。再利用可能なモジュールを作成し、識別子へのアクセスを制御し、コードをより整理して、より保守可能で拡張可能な Go アプリケーションを作成できます。
Summary
In this lab, you learned:
- How to create and define custom packages in Go, encapsulating reusable code.
- The difference between public (exported) and private (unexported) identifiers and how they impact accessibility.
- Various ways to import packages, each with its use case:
- Single-item import: Importing one package at a time.
- Grouped import: Importing multiple packages in a single block for better organization.
- Dot import: Importing a package and using its identifiers directly without the package name prefix. (Use with caution)
- Alias import: Renaming imported packages for better readability or to avoid naming conflicts.
- Anonymous import: Importing a package solely for its side effects, such as initialization.
- The role of the
init()function in packages and how anonymous imports can trigger its execution. - The detailed workings of Go's initialization process, including:
- How package-level variables are initialized before
init()functions - The guaranteed execution order of
init()functions across dependent packages - How multiple
init()functions work within a package - The complete initialization flow from dependent packages to the main function
- How package-level variables are initialized before
By completing this lab, you are now equipped to structure and manage Go projects using packages effectively. You can create reusable modules, control access to identifiers, better organize your code, and understand the initialization process, leading to more maintainable and scalable Go applications.



