mcpField
G
go-interfaces

go-interfaces

github.com/cxuu開発1861.3k 回インストール19 週間前に更新
リポジトリ

go-interfaces について

Go の API を設計する開発者向けに、インターフェース、型アサーション、埋め込み、レシーバーの選択を扱うスキルです。適合性確認用のスクリプトと資料も含みます。

主な機能

  1. 01利用側で定義するインターフェース
  2. 02具体型とインターフェースの返却指針
  3. 03安全な型アサーションと型スイッチ
  4. 04埋め込みとレシーバー型の指針
  5. 05コンパイル時の適合性チェック

活用シーン

  1. 01パッケージ API とコンストラクターの設計
  2. 02型のインターフェース適合性の確認
  3. 03公開構造体の埋め込みの見直し

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cxuu/golang-skills --skill go-interfaces

インストール後、Claude Code で/go-interfacesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
EMBEDDING.md
RECEIVER-TYPE.md
scripts/
check-interface-compliance.go
check-interface-compliance.sh

詳細

Go のインターフェースとコンポジション

リソースルーティング

  • scripts/check-interface-compliance.sh - コンパイル時アサーションが必要な可能性のあるエクスポート済みインターフェースを見つけるためのヒューリスティックとして実行します。
  • scripts/check-interface-compliance.go - check-interface-compliance.sh から呼び出される実装ヘルパーです。メソッドセットの分析を変更する場合は、このファイルを修正してください。
  • references/EMBEDDING.md - 公開 API でインターフェースや構造体を埋め込む場合に読んでください。
  • references/RECEIVER-TYPE.md - ポインタレシーバーと値レシーバーがインターフェースの充足に影響する場合に読んでください。

インターフェースを受け取り、具体型を返す

インターフェースは、値を実装するパッケージではなく、値を利用するパッケージに置きます。コンストラクターから具体型(通常はポインター型または構造体型)を返すと、リファクタリングせずに新しいメソッドを追加できます。

// Good: consumer defines the interface it needs
package consumer

type Thinger interface { Thing() bool }

func Foo(t Thinger) string { ... }
// Good: producer returns concrete type
package producer

type Thinger struct{ ... }
func (t Thinger) Thing() bool { ... }
func NewThinger() Thinger { return Thinger{ ... } }
// Bad: producer defines and returns its own interface
package producer

type Thinger interface { Thing() bool }
type defaultThinger struct{ ... }
func NewThinger() Thinger { return defaultThinger{ ... } }

使用される前にインターフェースを定義しないでください。 現実的な使用例がなければ、そもそもインターフェースが必要かどうかを判断するのが難しくなります。


汎用性:実装を隠し、インターフェースを公開する

型が、エクスポートされたメソッドをそのインターフェース以外に持たず、インターフェースの実装だけを目的としている場合は、実装を隠すためにコンストラクターからインターフェースを返します。

func NewHash() hash.Hash32 {
    return &myHash{}  // unexported type
}

利点:呼び出し側に影響を与えずに実装を変更できます。アルゴリズムを差し替えるには、コンストラクターの呼び出しを変更するだけで済みます。


型アサーション:カンマ ok イディオム

確認せずにアサーションすると、失敗時にランタイムパニックが発生します。安全にテストするには、常にカンマ ok イディオムを使用してください。

str, ok := value.(string)
if ok {
    fmt.Printf("string value is: %q\n", str)
}

値がインターフェースを実装しているか確認するには、次のようにします。

if _, ok := val.(json.Marshaler); ok {
    fmt.Printf("value %v implements json.Marshaler\n", val)
}

型スイッチ

変数名を再利用する(t := t.(type))のが慣用的です。各 case 分岐では、変数が適切な型になります。複数の型を列挙する case(case int, int64:)では、変数はインターフェース型になります。


埋め込み

公開構造体への型の埋め込みは避けてください。内部の型のメソッドセット全体が公開 API の一部になります。代わりに、非エクスポートフィールドを使用してください。


インターフェースの充足チェック

ブランク識別子への代入を使うと、型がインターフェースを実装していることをコンパイル時に検証できます。

var _ json.Marshaler = (*RawMessage)(nil)

*RawMessage が json.Marshaler を実装していない場合、コンパイルエラーになります。

次の場合にこのパターンを使用してください。

  • インターフェースを自動的に検証する静的変換がない
  • 正しい動作のために型がインターフェースを満たす必要がある(例:カスタム JSON マーシャリング)
  • インターフェースの変更によって、静かに動作が劣化するのではなく、コンパイルエラーが発生するべき

すべてのインターフェースにこれらのチェックを追加しないでください。他の静的変換でエラーを検出できない場合に限って追加してください。

検証:インターフェースまたは実装を定義した後、bash scripts/check-interface-compliance.sh を実行し、すべての具象型にコンパイル時の var _ I = (*T)(nil) チェックがあることを確認してください。


レシーバー型

迷った場合は、ポインタレシーバーを使用してください。1つの型でレシーバー型を混在させないでください。ポインターが必要なメソッドが1つでもあれば、すべてのメソッドでポインターを使用してください。値レシーバーを使用するのは、小さく不変な型(Point、time.Time)または基本型に限ります。


クイックリファレンス

概念パターン備考
利用側がインターフェースを所有使用する場所でインターフェースを定義する実装するパッケージには置かない
安全な型アサーションv, ok := x.(Type)ゼロ値と false を返す
型スイッチswitch v := x.(type)変数は case ごとに適切な型になる
インターフェースの埋め込みtype RW interface { Reader; Writer }メソッドの集合
構造体の埋め込みtype S struct { *T }T のメソッドを昇格させる
インターフェースチェックvar _ I = (*T)(nil)コンパイル時検証
汎用性コンストラクターからインターフェースを返す実装を隠す

関連スキル

  • インターフェースの命名:インターフェースの命名(-er サフィックスの慣習)やレシーバー名の選択については、go-naming を参照してください
  • エラー型:error インターフェース、カスタムエラー型、または errors.As によるマッチングを実装する際は、go-error-handling を参照してください
  • ジェネリクスとインターフェースの比較:ジェネリクスが必要か、既存のインターフェースで十分かを判断する際は、go-generics を参照してください
  • 関数型オプション:柔軟なコンストラクターにインターフェースベースの Option パターンを使用する際は、go-functional-options を参照してください
  • 防御的な境界処理:インターフェースのアサーションが、より広範な API 境界の堅牢化作業の一部である場合は、go-defensive を参照してください

コメント