Goのエラー「cannot refer to unexported name」の解決方法

beginner🔷 Go2026-04-30| Go (Golang) コンパイラ、バージョン 1.0 から 1.23以降。Linux、macOS、Windowsに対応。

Error Message

cannot refer to unexported name package.name
#go#golang#可視性#エクスポート#カプセル化

10秒で解決

Goでは、先頭の文字が大文字か小文字かによって可視性が決まります。cannot refer to unexported nameエラーが発生した場合、定義されているパッケージの外側から、小文字で始まる識別子(アンエクスポートな名前)にアクセスしようとしています。

関数、変数、または型の定義場所で、先頭の文字を大文字にしてエクスポート(公開)してください。

// 'auth' パッケージ内 (auth/token.go)
func validateToken() { ... } // 非公開:外部から呼び出すとエラーになります
func ValidateToken() { ... } // 公開:修正済み、エクスポートされました

定義の名前を変更したら、他のパッケージで呼び出している箇所も、大文字で始まる新しい名前に更新してください。最新のIDEの多くは、このリファクタリングを数秒で自動実行できます。

原因:パッケージレベルのスコープ

JavaやC#の経験がある方は、publicprivateといったキーワードを探してしまうかもしれません。しかし、Goにはそれらがありません。代わりに、文字のケース(大文字・小文字)に基づいたシステムが採用されています。

  • 大文字 (A-Z): エクスポートされます。パブリックであり、インポートしたどのパッケージからでもアクセス可能です。
  • 小文字 (a-z): エクスポートされません(アンエクスポート)。そのパッケージ(ディレクトリ)内でのみ利用可能なプライベートな存在です。

コンパイラはこのルールを厳格に適用します。go buildを実行すると、すべての参照が可視性ルールに従っているかチェックされます。パッケージの境界を越えて小文字の識別子が使用されている場合、コードのカプセル化を保護するためにビルドが停止します。

よくあるシナリオ

1. 関数と変数のエクスポート

共通のユーティリティパッケージなどを構築している際によく発生します。最初はヘルパー関数として書き始め、後からメインのアプリケーションロジックで必要になった場合などです。

問題:

// internal/formatter/text.go
package formatter

func formatUserString(s string) string { ... }

// main.go
package main
import "myproject/internal/formatter"

func main() {
    // エラー:cannot refer to unexported name formatter.formatUserString
    fmt.Println(formatter.formatUserString("hello"))
}

解決策: formatUserStringFormatUserStringに変更します。Go 1.23以前のすべてのバージョンにおいて、例外なくこのルールが適用されます。

2. プライベートな構造体フィールドとJSON

構造体自体がエクスポートされていても、各フィールドが小文字で始まっている場合はプライベートなままです。これはencoding/jsonパッケージを使用する際によくある落とし穴です。JSONのMarshal/Unmarshal処理は外部パッケージで実行されるため、あなたのコードのプライベートフィールドを見ることはできません。

エラーになるコード:

// models/user.go
type User struct {
    Name string
    email string // 非公開:他のパッケージからは見えません
}

// main.go
u := models.User{Name: "Bob", email: "bob@example.com"} // コンパイルエラー

修正方法: フィールド名をEmailに変更します。APIとのやり取りでシリアライズする場合は、構造体タグを使用して、Goのフィールドはエクスポートしつつ、JSONのキーは小文字に保つことができます。

type User struct {
    Name  string `json:"name"` 
    Email string `json:"email"` // アクセス可能で、APIの命名規則に従います
}

3. 定数と型

定数やカスタム型も同じルールに従います。configパッケージ内でtype duration intを定義した場合、それをDurationにリネームしない限り、サービスレイヤーで関数の引数として使用することはできません。

読み取り専用アクセスのための「Getter」パターン

何でもエクスポートすれば良いというわけではありません。他のパッケージに値の読み取りは許可したいが、変更はさせたくない場合もあります。そのような時は、変数は小文字(非公開)のままにし、その値を返すエクスポートされた関数を提供します。

package db

// 非公開変数により、他のパッケージからの予期しない上書きを防止します
var connectionString = "root:password@website/content/errors/en/docker/fix-dial-tcp-lookup-db-on-12700153-no-such-host-in-docker-compose.md(127.0.0.1:3306)/app_db"

// ConnectionString は安全な読み取り専用アクセスを提供します
func ConnectionString() string {
    return connectionString
}

検証とリファクタリング

修正を確認するには、プロジェクトのフルチェックを実行します。go build ./...を使用して、モジュール内のすべてのパッケージをコンパイルします。コマンドが何も出力せずに終了すれば、すべての可視性の問題が解決したことになります。

非公開名への参照が何百箇所もある場合は、手動で修正してはいけません。エディタのリファクタリングツールを活用しましょう。

  • VS Code: 名前の上にカーソルを置いて F2 キーを押します。
  • GoLand: Shift + F6 を使用します。
  • CLI: プログラムから一括変更するには gopls rename を使用します。

これらのツールを使えば、プロジェクト全体のすべての箇所が即座に更新されます。手動の「検索と置換」による疲労や、新しいバグの混入を防ぐことができます。

Related Error Notes