2026年のGo言語インターフェース完全攻略:合成、型アサーション、面接対策
Go 1.26の自己参照ジェネリクスを含む、インターフェース合成と型アサーションを徹底解説。実践的なコード例と技術面接でよく聞かれる質問も網羅。

Goのインターフェースは、実装を規定せずに振る舞いを定義することで、柔軟でテストしやすいコードの核となります。Go 1.26では、自己参照ジェネリクス、新しいリフレクションイテレータ、errors.AsTypeによる型安全なエラー処理が追加されました。本記事では、インターフェース合成、型アサーション、埋め込みパターン、そして技術面接で問われる質問について解説します。
ジェネリック型が型パラメータリスト内で自身を参照できるようになりました:type Adder[A Adder[A]] interface { Add(A) A }。このF境界量化パターンにより、戻り値の型を実装型自身に制約するインターフェースが実現できます。
インターフェース合成と埋め込みパターン
インターフェースの埋め込みは、複数のインターフェースを単一の契約に結合します。結果として、埋め込まれたすべてのインターフェースのメソッドを要求する新しいインターフェースが生成されます。このパターンは重複を避け、明確な抽象化の境界を作成します。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
// Composed interface embedding three interfaces
type ReadWriteCloser interface {
Reader
Writer
Closer
}Read、Write、Closeメソッドを実装する任意の型は、自動的にReadWriteCloserを満たします。Go標準ライブラリのioパッケージでは、このパターンが広く使用されています。
面接でよく聞かれる質問として、「なぜGoは小さく焦点を絞ったインターフェースを好むのか」というものがあります。その答えは合成可能性にあります:io.Readerは、たった1つのメソッドを要求するだけで、数百の関数で使用されています。大きなインターフェースは結合を強くし、再利用性を低下させます。
型アサーション:構文と安全性
型アサーションは、インターフェース値から具象型を抽出します。2値形式を使用することで、成功を示すブール値を返し、パニックを防ぎます。
func processValue(v interface{}) {
// Two-value assertion: safe, no panic
if str, ok := v.(string); ok {
fmt.Printf("String value: %s\n", str)
return
}
// Type switch for multiple types
switch val := v.(type) {
case int:
fmt.Printf("Integer: %d\n", val)
case float64:
fmt.Printf("Float: %.2f\n", val)
case []byte:
fmt.Printf("Bytes: %x\n", val)
default:
fmt.Printf("Unknown type: %T\n", val)
}
}型スイッチは、複数の可能な型をきれいに処理します。各ケースではvalがそのブロック内でアサートされた型に束縛されるため、個別のアサーションは不要です。
str := v.(string)のような単一値アサーションは、アサーションが失敗するとパニックします。本番コードでは常に2値形式または型スイッチを使用してください。
面接では型アサーションのパフォーマンスについて質問されることがあります。ランタイムは型記述子の単一の比較を行うため、アサーションは低コストです。大きな構造体へのポインタをラップするインターフェース値では間接参照のためコストが増加しますが、アサーション自体はO(1)のままです。
Go 1.26の自己参照ジェネリクス
Go 1.26では自己参照型パラメータが導入され、メソッドが実装型を返す必要があるインターフェースが可能になりました。このパターンはF境界量化と呼ばれ、長年の制限を解決しています。
// Self-referential interface: methods return the same type
type Builder[B Builder[B]] interface {
WithName(name string) B
WithAge(age int) B
Build() string
}
type PersonBuilder struct {
name string
age int
}
func (p PersonBuilder) WithName(name string) PersonBuilder {
p.name = name
return p
}
func (p PersonBuilder) WithAge(age int) PersonBuilder {
p.age = age
return p
}
func (p PersonBuilder) Build() string {
return fmt.Sprintf("%s, %d years old", p.name, p.age)
}
// Generic function using the self-referential constraint
func configure[B Builder[B]](b B, name string, age int) string {
return b.WithName(name).WithAge(age).Build()
}制約Builder[B]は、WithNameとWithAgeがジェネリックなBuilderではなくBを返すことを保証します。これがなければ、戻り値の型はインターフェースとなり、具象型の情報が失われ、メソッドチェーンが壊れてしまいます。
数学型もこのパターンの恩恵を受けます。Addable[A Addable[A]]インターフェースは、Add(A) Aが同じ数値型を返すことを保証し、BigIntとDecimalの値の誤った混在を防ぎます。
errors.AsType:型安全なエラーアンラップ
Go 1.26ではerrors.AsTypeが追加され、errors.Asのポインタを使用したパターンが置き換えられました。ジェネリック版はアンラップされたエラーを直接返します。
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
}
func handleError(err error) {
// Go 1.26: generic type-safe unwrapping
if valErr, ok := errors.AsType[*ValidationError](err); ok {
log.Printf("Validation error on field %s\n", valErr.Field)
return
}
// Before Go 1.26: pointer-based unwrapping
// var valErr *ValidationError
// if errors.As(err, &valErr) { ... }
log.Printf("Unexpected error: %v\n", err)
}新しいAPIは、別々の変数宣言を不要にし、関数呼び出しでターゲット型を明示的にします。エラーチェーンは以前と同じ方法で検索されます。変わったのはインターフェースだけです。
Goの面接対策はできていますか?
インタラクティブなシミュレーター、flashcards、技術テストで練習しましょう。
インターフェース検査のためのリフレクションイテレータ
Go 1.26ではreflectパッケージにイテレータメソッドが追加されました。Type.Methods()とValue.Methods()はメソッドを反復処理するためのイテレータを返し、インデックスベースのループを置き換えます。
import "reflect"
func inspectInterface(v interface{}) {
t := reflect.TypeOf(v)
// Go 1.26: iterator-based method inspection
fmt.Printf("Type %s methods:\n", t.Name())
for method := range t.Methods() {
fmt.Printf(" %s: %s\n", method.Name, method.Type)
}
// For struct fields (also new in 1.26)
if t.Kind() == reflect.Struct {
for field := range t.Fields() {
fmt.Printf(" Field: %s (%s)\n", field.Name, field.Type)
}
}
}イテレータパターンはGo 1.23のrange-over-function機能と整合しています。コードはより読みやすくなり、パフォーマンスのペナルティはありません:イテレータは遅延評価で値を生成します。
コンパイル時のインターフェース満足チェック
Goは、具象値をインターフェース変数に代入する際にコンパイル時にインターフェース満足をチェックします。空白識別子代入を使用した明示的なチェックにより、大規模なコードベースでエラーを早期に検出できます。
type Storage interface {
Save(key string, data []byte) error
Load(key string) ([]byte, error)
Delete(key string) error
}
type FileStorage struct {
basePath string
}
// Compile-time check: fails if FileStorage misses a method
var _ Storage = (*FileStorage)(nil)
func (f *FileStorage) Save(key string, data []byte) error {
path := filepath.Join(f.basePath, key)
return os.WriteFile(path, data, 0644)
}
func (f *FileStorage) Load(key string) ([]byte, error) {
path := filepath.Join(f.basePath, key)
return os.ReadFile(path)
}
func (f *FileStorage) Delete(key string) error {
return os.Remove(filepath.Join(f.basePath, key))
}var _ Storage = (*FileStorage)(nil)という行は、*FileStorageがStorageを満たす場合にのみコンパイルされます。このパターンは、値が代入される実行時ではなく、欠落しているメソッドを即座に検出します。
空インターフェースと型制約
空インターフェースinterface{}は任意の値を受け入れ、anyはGo 1.18以降そのエイリアスです。ジェネリック制約は、実行時アサーションなしでコンパイル時の型安全性を提供します。
import "golang.org/x/exp/constraints"
// Generic function with numeric constraint
func Sum[T constraints.Integer | constraints.Float](values []T) T {
var total T
for _, v := range values {
total += v
}
return total
}
// Comparable constraint for map keys
func Contains[K comparable, V any](m map[K]V, key K) bool {
_, exists := m[key]
return exists
}interface{}よりもジェネリクスを優先することで、型アサーションが不要になり、コンパイル時に型の不一致を検出できます。トレードオフは関数シグネチャの複雑さが増すことなので、ジェネリクスは関数が本当に複数の型を操作する場合に最適です。
Goインターフェースに関する技術面接の質問
面接官は複数のレベルでインターフェースの知識をテストします。以下は一般的な質問と簡潔な回答です。
Q:nilインターフェース値でメソッドを呼び出す場合と、インターフェース内のnil具象値でメソッドを呼び出す場合、何が起こりますか?
nilインターフェースは型も値も持たないため、任意のメソッドを呼び出すとパニックします。nilポインタを保持する非nilインターフェースは型を持っているため、メソッドはnilレシーバで実行されます。この動作により、(*bytes.Buffer)(nil).String()が空文字列を返すようなパターンが可能になります。
Q:インターフェースの比較はどのように機能しますか?
2つのインターフェース値は、同じ動的型と等しい動的値を持つ場合に等しくなります。比較不可能な型(スライス、マップ、関数)を持つインターフェースを比較すると、実行時にパニックします。
Q:メソッドはポインタレシーバと値レシーバのどちらを使用すべきですか?
ポインタレシーバは変更を可能にし、大きな構造体のコピーを回避します。値レシーバは並行使用に安全で、値とポインタの両方で動作します。いずれかのメソッドがポインタレシーバを必要とする場合、一貫性のためにその型のすべてのメソッドがポインタレシーバを使用すべきです。なぜなら、ポインタレシーバメソッドを必要とするインターフェースを満たすのは*Tだけだからです。
type Counter struct {
count int
}
// Pointer receiver: modifies the struct
func (c *Counter) Increment() {
c.count++
}
// Value receiver: read-only operation
func (c Counter) Value() int {
return c.count
}
type Incrementer interface {
Increment()
}
func main() {
var c Counter
// var i Incrementer = c // Compile error: Counter lacks Increment
var i Incrementer = &c // OK: *Counter has Increment
i.Increment()
}Q:「インターフェースを受け入れ、構造体を返す」原則を説明してください。
インターフェースを受け入れる関数は具象実装から分離され、モックによるテストが可能になります。具象型を返すことで、呼び出し側は型アサーションなしでその型のすべてのメソッドにアクセスできます。インターフェースを返すと、将来のメソッド追加が型アサーションの背後に隠されてしまいます。
Goの面接対策については、並行性パターンの面接質問モジュールやテストモジュールも参照してください。
インターフェースの設計を求められた場合、まず単一メソッドのケースから始めてください。複数のメソッドが常に一緒に呼び出される場合にのみ拡張します。標準ライブラリのStringer、Reader、Handlerインターフェースは、それぞれ1つのメソッドを定義しています。
シニアGo開発者がインターフェースについて知っておくべきこと
- 埋め込みによるインターフェース合成は、継承階層なしで柔軟な契約を作成します。インターフェースは小さく保ちましょう:1〜3メソッドでほとんどのユースケースをカバーできます。
- 型アサーションと型スイッチは具象型を安全に抽出します。パニックを避けるため、本番コードでは常に2値形式またはスイッチを使用してください。
- Go 1.26の自己参照ジェネリクスは、メソッドが実装型を返す必要があるビルダーパターンや数学型を可能にします。
errors.AsTypeはジェネリックで型安全なAPIでエラーアンラップを簡素化します。Go 1.26以降をターゲットとする新しいコードで使用してください。var _ Interface = (*Type)(nil)によるコンパイル時インターフェースチェックは、テスト実行前に欠落メソッドを検出します。- コンパイル時の型安全性がシグネチャの複雑さを上回る場合、
interface{}よりもジェネリクスを優先してください。 - 「インターフェースを受け入れ、構造体を返す」ガイドラインは、呼び出し側に柔軟性を維持しながら完全な機能を公開します。
今すぐ練習を始めましょう!
面接シミュレーターと技術テストで知識をテストしましょう。
Go のバグを見つけられますか
実際のコード、隠れたバグ、1日1回。アカウントなしで試せます。

執筆
Anthony Fillion-MailletSharpSkill 創業者
10 年以上フルスタック開発に携わっています。SharpSkill を運営し、ここで公開される内容に責任を負っています。
2026年9月10日 更新
タグ
共有
関連記事

Go 1.26面接対策:Green Tea GC、go fixツール、スタック最適化の徹底解説
Go 1.26の面接対策として、新しいGreen Teaガベージコレクタ、刷新されたgo fixツール、スライスのスタック割り当て最適化など、主要な変更点を詳しく解説します。

Go エラーハンドリング 2026年版:パターン、ラッピング、技術面接の頻出質問
Goのエラーハンドリングパターンを網羅的に解説。センチネルエラー、カスタム型、errors.Is・errors.As、%wによるエラーラッピング、技術面接で頻出の質問まで幅広くカバー。

Goデザインパターン:Go開発者が押さえるべき必須パターンと面接対策
Goの設計思想に基づくデザインパターンを体系的に解説。Functional Options、Strategy、Observer、Middlewareなど、面接で問われる実践的パターンとその回答例を紹介します。