Goコードを正しく構造化する方法を学ぶ:単一ファイルのプロジェクトからパッケージ、内部モジュール、適切なインポートまで、計算機の例で説明します。Goコードを正しく構造化する方法を学ぶ:単一ファイルのプロジェクトからパッケージ、内部モジュール、適切なインポートまで、計算機の例で説明します。

プロのようにGoプロジェクトを整理する方法

2025/10/06 11:36
10 分で読めます
本コンテンツに関するご意見・ご感想は、crypto.news@mexc.comまでご連絡ください。

\ Goを学び始めたとき、最初に持った疑問の1つは:

「実際にコードをどのように構造化すればいいのか?」

Cのような言語では、すべてを1つのファイルに入れるか、ヘッダーと実装ファイルを分けるのが一般的です。しかしGoでは、プロジェクト構造が重要です:それはコードのスケーラビリティ、テスト、共有のしやすさに影響します。この記事では、なぜ構造が重要なのか、異なるファイルから関数にアクセスする方法、そして私が前進するにつれて学んでいるベストプラクティスについて説明します。


最もシンプルなGoプログラム

Goプログラムは完全に1つのファイルに収めることができます:

package main  import "fmt"  func main() {   fmt.Println("2 + 2 =", 2+2) } 

これは「hello world」や簡単な実験には適しています。

しかし、より多くの機能(減算、乗算、除算など)を追加するとすぐに、ファイルは乱雑になりスケーラビリティが低下します。

ここでGoのパッケージフォルダが役立ちます。


パッケージの紹介

Goでは、すべてのファイルがパッケージに属します。

慣例により:

  • main → 実行可能プログラム
  • その他(calculator、utilsなど)→ 再利用可能なロジック

計算機プロジェクトをこのように分割しました:

calculator/ │ ├── main.go └── calculator/     └── operations.go 

\

  • main.go → 入出力を処理
  • operations.go → Add、Subtractなどの関数を定義

例:operations.go

package calculator  func Add(a, b int) int {   return a + b }  func Subtract(a, b int) int {   return a - b }  func Multiply(a, b int) int {   return a * b }  func Divide(a, b int) (int, error) {   if b == 0 {     return 0, fmt.Errorf("cannot divide by zero")   }   return a / b, nil } 

例:main.go

package main  import (   "fmt"   "GoLang-progress/calculator" )  func main() {   fmt.Println("2 + 3 =", calculator.Add(2, 3))   fmt.Println("10 - 4 =", calculator.Subtract(10, 4))   fmt.Println("6 * 7 =", calculator.Multiply(6, 7))    result, err := calculator.Divide(8, 0)   if err != nil {     fmt.Println("Error:", err)   } else {     fmt.Println("8 / 0 =", result)   } } 

main.goがクリーンになったことに注目してください:数学自体を気にする必要はなく、使い方だけを考えればよいのです。


異なるファイルから関数にアクセスする

初心者によくある質問:

「別のファイルやフォルダから関数を呼び出すにはどうすればいいですか?」

私のリポジトリでは、このように構造化しました:

calculator/ │ ├── main.go └── internal/     └── calc/         └── operations.go 

ここでは、数学関数はinternal/calcの下にあります。

operations.go(internal/calcの中)

\

package calc  import "fmt"  func Add(a, b int) int {   return a + b }  func Divide(a, b int) (int, error) {   if b == 0 {     return 0, fmt.Errorf("cannot divide by zero")   }   return a / b, nil } 

main.go(internal/calcをインポート)

\

package main  import (   "fmt"   "github.com/turman17/GoLang-progress/calculator/internal/calc" )  func main() {   fmt.Println("2 + 3 =", calc.Add(2, 3))    result, err := calc.Divide(10, 0)   if err != nil {     fmt.Println("Error:", err)   } else {     fmt.Println("10 / 2 =", result)   } } 

なぜこのインポートパスが必要なのか

インポートはgo.modのモジュールパスとフォルダパスに一致する必要があります。

あなたのリポジトリでは、go.modには次のように記述されています:

module github.com/turman17/GoLang-progress 

使用したい計算機コードはこのフォルダにあります:

calculator/internal/calc 

したがって、完全なインポートパスは:

github.com/turman17/GoLang-progress/calculator/internal/calc 

いくつかの重要な注意点

  • フォルダ名 ≠ パッケージ名 → フォルダはinternal/calcですが、内部のパッケージはpackage calcとして宣言されています。
  • インポートはモジュールパスを使用 → go.modにgithub.com/...がある場合は、常にそれで始めます。
  • internalは特別 → /internal以下のパッケージは同じモジュール内のコードからのみインポートできます。

よくあるエラーと修正方法

❌ import "GoLang-progress/calculator/internal/calc"

→ GitHubの組織/ユーザー名が欠けています。完全なパスを使用する必要があります。

❌ import "github.com/turman17/GoLang-progress/internal/calc"

→ パスにcalculatorディレクトリが欠けています。

❌ go: module not found errors

→ go.modにmodule github.com/turman17/GoLang-progressがあることを確認し、go mod tidyを実行してください。


クイックチェックリスト

  • go.modに正しいモジュール行がある
  • ディレクトリはcalculator/internal/calcで、内部にpackage calcがある
  • main.goはgithub.com/turman17/GoLang-progress/calculator/internal/calcをインポートする
  • モジュールのルートからビルドする:

\

go run ./calculator 

または

go build ./calculator 

構造のスケーリング

プロジェクトが成長するにつれて、よく見られるパターンは次のとおりです:

project-name/ │ ├── cmd/        → 実行可能ファイル(メインエントリーポイント) ├── internal/   → プライベートコード(外部使用不可) ├── pkg/        → 再利用可能なパッケージ ├── api/        → API定義(gRPC、OpenAPIなど) └── go.mod 

初心者にとっては、これは過剰かもしれません。しかし、ウェブアプリ、サービス、またはMLOpsツールに移行するにつれて、このレイアウトは不可欠になります。


学んでいるベストプラクティス

  • パッケージを小さく焦点を絞ったものにする
  • 意味のある名前を使用する(calc、parser、storageなど)
  • 過剰なエンジニアリングを避ける — シンプルに始めて、後でリファクタリングする
  • 循環依存を避ける(Goはこれを強制します)

計算機プロジェクトから学んだ教訓

  • ロジック(operations.go)をエントリーポイント(main.go)から分離することで、テストが容易になります。
  • エラー処理(ゼロ除算など)は明示的であるべきです。
  • インポートパスは本当に重要です — 特にinternalを使用する場合。

MLOpsとバックエンド開発のためにGoを探求する中で、学んだことを引き続き共有していきます。次回は:Goでのエラー処理とテストについてです。

\ 👉 私のリポジトリはこちら:https://github.com/turman17/GoLang-progress

次の記事もお楽しみに!

免責事項:このサイトに転載されている記事は、公開プラットフォームから引用されており、情報提供のみを目的としています。MEXCの見解を必ずしも反映するものではありません。すべての権利は原著者に帰属します。コンテンツが第三者の権利を侵害していると思われる場合は、削除を依頼するために crypto.news@mexc.com までご連絡ください。MEXCは、コンテンツの正確性、完全性、適時性について一切保証せず、提供された情報に基づいて行われたいかなる行動についても責任を負いません。本コンテンツは、財務、法律、その他の専門的なアドバイスを構成するものではなく、MEXCによる推奨または支持と見なされるべきではありません。

$30,000相当のPRL + 15,000 USDT

$30,000相当のPRL + 15,000 USDT$30,000相当のPRL + 15,000 USDT

PRLを入金&取引して、報酬を最大化!