[インデックス 19470] ファイルの概要
このコミットは、Go言語のcgo
ツールに関するドキュメントの更新です。具体的には、cgo
がC言語の型をGo言語の型に変換する際に、それらのGo言語の型が「非公開(unexported)」となること、そしてその結果として、Goパッケージが公開APIでC言語の型を直接使用すべきではないという重要な注意点を明記しています。これにより、cgo
を利用する開発者がGoのパッケージシステムと型の可視性に関する規則をより深く理解し、予期せぬ問題(特に異なるパッケージ間でC言語の型を共有しようとした場合)を避けることを目的としています。
コミット
commit 3f66c0c07b271af796765ce5e9e9c21a86ddb0d7
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Sat May 31 00:51:46 2014 -0700
cmd/cgo: document the cgo types also follow Go name space rules.
Fixes #7958.
LGTM=rsc
R=golang-codereviews, rsc, r, gobot
CC=golang-codereviews
https://golang.org/cl/91520043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3f66c0c07b271af796765ce5e9e9c21a86ddb0d7
元コミット内容
cmd/cgo
: cgoの型もGoの名前空間ルールに従うことを文書化。
Issue #7958を修正。
変更の背景
このコミットの背景には、cgo
を使用してC言語のコードをGo言語から呼び出す際に、C言語の型がGo言語の型にどのように変換され、Goのパッケージシステム内でどのように振る舞うかについての誤解や不明瞭さがあったと考えられます。特に、Go言語における「公開(exported)」と「非公開(unexported)」の概念が、cgo
によって生成される型にも適用されるという点が重要です。
Go言語では、識別子(変数、関数、型など)がパッケージ外からアクセス可能かどうかは、その識別子の名前が大文字で始まるか小文字で始まるかによって決まります。大文字で始まる識別子は公開され、小文字で始まる識別子は非公開となり、そのパッケージ内でのみアクセス可能です。
cgo
はC言語の型(構造体、共用体、列挙型など)をGo言語の対応する型に変換しますが、この変換されたGoの型は、Goの命名規則に従って非公開として扱われます。このため、あるGoパッケージでcgo
を介してCの型を定義し、それを別のGoパッケージの公開APIで使用しようとすると、型が一致しないという問題が発生する可能性がありました。これは、Goの型システムが、異なるパッケージで定義された非公開の型を、たとえそれらが同じ基盤を持つCの型から変換されたものであっても、異なる型として扱うためです。
このコミットは、このような潜在的な混乱やバグを防ぐために、cgo
のドキュメントにこの重要な挙動を明記することを目的としています。Fixes #7958
という記述がありますが、Goの公式Issueトラッカーで直接この番号のIssueを見つけることはできませんでした。しかし、このコミットが特定のユーザーの混乱や問題提起に対応したものであることは明らかです。
前提知識の解説
cgo
cgo
は、Go言語のプログラムからC言語のコードを呼び出すためのGoツールチェーンの一部です。Goのソースファイル内に特別なimport "C"
という擬似パッケージを記述し、その直前のコメントブロックにC言語のコードを記述することで、GoとCの相互運用を可能にします。cgo
は、Goのビルドプロセス中にCのコードをコンパイルし、Goのコードとリンクするための接着コード(glue code)を生成します。
Go言語のパッケージと名前空間
Go言語は、コードを整理し、再利用性を高めるためにパッケージシステムを採用しています。各Goファイルは特定のパッケージに属し、パッケージは関連する機能の集合体です。
Goの名前空間ルールにおいて重要なのは、識別子の可視性です。
- 公開(Exported): 識別子(変数、関数、型、メソッドなど)の名前が大文字で始まる場合、その識別子はパッケージ外からアクセス可能です。これは、そのパッケージの公開APIの一部となります。
- 非公開(Unexported): 識別子の名前が小文字で始まる場合、その識別子は定義されたパッケージ内でのみアクセス可能です。パッケージ外からは直接参照できません。
このルールは、Goの型システムにも適用されます。例えば、package foo
で定義されたtype MyStruct struct {}
と、package bar
で定義されたtype MyStruct struct {}
は、たとえフィールドが同じであっても、異なる型として扱われます。さらに、package foo
で定義された非公開の型type myStruct struct {}
は、package foo
内でのみmyStruct
として認識され、他のパッケージからはその型名で直接参照することはできません。
cgoにおけるC言語の型のGo言語への変換
cgo
は、C言語の構造体、共用体、列挙型などをGo言語の対応する型に変換します。例えば、Cのstruct MyCStruct { int x; }
は、Goのstruct
に変換されます。しかし、この変換されたGoの型は、Goの命名規則に従って非公開の識別子として扱われます。これは、cgo
が生成するGoの型名が、通常、小文字で始まるか、あるいはGoのパッケージシステムが内部的に非公開として扱うような方法で生成されるためです。
この「非公開」という特性が、異なるGoパッケージ間でcgo
によって変換されたCの型を共有しようとする際に問題を引き起こします。Goの型システムは、異なるパッケージで定義された非公開の型を、たとえそれらが同じCの型から派生したものであっても、互換性のない異なる型として扱います。
技術的詳細
このコミットが追加するドキュメントは、cgo
がC言語の型をGo言語の型に変換する際の重要な側面を明確にしています。
-
CgoはCの型を同等の非公開Go型に変換する:
Cgo translates C types into equivalent unexported Go types.
これは、cgo
がCのstruct
やunion
などをGoのstruct
やarray
にマッピングする際に、生成されるGoの型がその型を定義したGoパッケージの外部からは直接アクセスできない(非公開である)ことを意味します。例えば、Cのtypedef struct { int x; } MyCStruct;
があった場合、cgo
はこれをGoの内部的な型(例えば_Ctype_struct_MyCStruct
のような名前で、Goの命名規則上は非公開となる)に変換します。 -
非公開であるため、Goパッケージは公開APIでCの型を公開すべきではない:
Because the translations are unexported, a Go package should not expose C types in its exported API:
この点は非常に重要です。もしGoパッケージが、cgo
によって変換されたCの型を、そのパッケージの公開関数やメソッドの引数、戻り値、あるいは公開構造体のフィールドとして使用しようとすると、そのパッケージを利用する他のGoパッケージは、その型を認識できません。結果として、コンパイルエラーや予期せぬ型不一致のエラーが発生します。 -
あるGoパッケージで使用されるCの型は、別のGoパッケージで使用される同じCの型とは異なる:
a C type used in one Go package is different from the same C type used in another.
これは、Goの型システムの厳密な性質を強調しています。Goでは、型は定義されたパッケージによってスコープが限定されます。たとえ同じCのヘッダーファイルをインポートしていても、異なるGoパッケージがそれぞれcgo
を介してCの型をGoの型に変換した場合、それらはGoの型システム上では全く異なる、互換性のない型として扱われます。これは、Goの型がその定義元パッケージのパスを含む完全修飾名を持つためです。非公開の型は、そのパッケージ内でのみユニークであり、他のパッケージからはその型名で参照できないため、異なるパッケージで同じCの型から生成された非公開のGo型は、Goのコンパイラにとっては別物となります。
このドキュメントの追加は、cgo
を使用する開発者が、Goの型システムとパッケージの可視性ルールを考慮した上で、堅牢で保守しやすいGoコードを書くためのガイドラインを提供します。特に、cgo
を介してCの型を扱う際には、Goの公開APIにはGoネイティブの型を使用し、Cの型はパッケージ内部にカプセル化することが推奨されるというメッセージを伝えています。
コアとなるコードの変更箇所
変更はsrc/cmd/cgo/doc.go
ファイルに対して行われました。これはcgo
ツールのドキュメントファイルです。
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -107,6 +107,11 @@ C's union types are represented as a Go byte array with the same length.
Go structs cannot embed fields with C types.
+Cgo translates C types into equivalent unexported Go types.
+Because the translations are unexported, a Go package should not
+expose C types in its exported API: a C type used in one Go package
+is different from the same C type used in another.
+
Any C function (even void functions) may be called in a multiple
assignment context to retrieve both the return value (if any) and the
C errno variable as an error (use _ to skip the result value if the
追加された行は以下の5行です。
Cgo translates C types into equivalent unexported Go types.
Because the translations are unexported, a Go package should not
expose C types in its exported API: a C type used in one Go package
is different from the same C type used in another.
コアとなるコードの解説
追加されたコードは、src/cmd/cgo/doc.go
というcgo
の公式ドキュメントファイルに、cgo
がC言語の型をGo言語の型に変換する際の重要な挙動に関する説明を追加しています。
-
Cgo translates C types into equivalent unexported Go types.
この行は、cgo
がC言語の型(例:struct
,union
,enum
)をGo言語の対応する型に変換する際に、それらのGo言語の型が「非公開(unexported)」として扱われることを明確に述べています。Goの命名規則では、小文字で始まる識別子は非公開であり、パッケージ内でのみアクセス可能です。cgo
が生成する内部的な型名もこのルールに従うため、外部からは直接参照できません。 -
Because the translations are unexported, a Go package should not
expose C types in its exported API: a C type used in one Go package
is different from the same C type used in another.
この3行は、上記の「非公開」という特性が持つ重要な意味合いを説明しています。- 公開APIでの使用の禁止: 変換されたGoの型が非公開であるため、Goパッケージは、その公開API(公開関数、公開構造体のフィールドなど)でこれらの型を直接公開すべきではありません。もし公開してしまうと、そのパッケージを利用する他のGoパッケージは、これらの型を認識できず、型不一致のエラーが発生します。
- 異なるパッケージ間での型の非互換性: さらに、あるGoパッケージで
cgo
を介してCの型がGoの型に変換された場合、それはそのパッケージ固有の非公開型となります。たとえ別のGoパッケージが同じCの型をcgo
で変換したとしても、Goの型システム上では、これらは互換性のない異なる型として扱われます。これは、Goの型がその定義元パッケージによって一意に識別されるためです。
このドキュメントの追加により、cgo
を使用する開発者は、Goのパッケージ設計において、C言語の型をGoの公開APIに漏らさないように注意する必要があることを明確に理解できます。これにより、cgo
を利用したGoプログラムの堅牢性と保守性が向上します。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- cgoの公式ドキュメント: https://go.dev/cmd/cgo/ (このコミットで変更されたファイルの内容が含まれます)
参考にした情報源リンク
- Go言語のパッケージと可視性に関する一般的な知識
cgo
の基本的な動作に関する知識- Go言語のIssueトラッカー(
#7958
の直接的なIssueは見つかりませんでしたが、コミットメッセージからその意図を推測しました)