インターフェースの定義と実装
暗黙的な実装と空のインターフェース
「インターフェースの定義と実装」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
インターフェースとは
Goのインターフェースは、メソッドシグネチャの集合です。それらすべてのメソッドを実装する型は、implementsキーワードなしで暗黙的にインターフェースを満たします。これは構造的型付け、またはダックタイピングと呼ばれます。
インターフェースの宣言
typeキーワードを使ってインターフェースを定義します:
package main
import "fmt"
type Shape interface {
Area() float64
Perimeter() float64
}
type Circle struct{ Radius float64 }
func (c Circle) Area() float64 { return 3.14159 * c.Radius * c.Radius }
func (c Circle) Perimeter() float64 { return 2 * 3.14159 * c.Radius }
func main() {
var s Shape = Circle{5}
fmt.Printf("Area: %.2f\n", s.Area())
}暗黙的にインターフェースを満たす
意図を宣言する必要はありません。型が適切なメソッドを持っていれば、自動的にインターフェースを満たします:
package main
import "fmt"
type Greeter interface{ Greet() string }
type English struct{}
func (e English) Greet() string { return "Hello" }
type Spanish struct{}
func (s Spanish) Greet() string { return "Hola" }
func say(g Greeter) { fmt.Println(g.Greet()) }
func main() {
say(English{})
say(Spanish{})
}空のインターフェース
interface{}(またはGo 1.18以降のany)は、すべての型によって満たされます。コンパイル時に型が不明な場合に使われます:
package main
import "fmt"
func printAny(v any) { fmt.Printf("%T: %v\n", v, v) }
func main() {
printAny(42)
printAny("hello")
printAny([]int{1,2,3})
}インターフェースの値
インターフェースの値は、具体的な型と具体的な値の2つを保持します。nilインターフェースでは、どちらもnilに設定されています:
package main
import "fmt"
type Animal interface{ Sound() string }
type Dog struct{}
func (d Dog) Sound() string { return "woof" }
func main() {
var a Animal
fmt.Println(a == nil) // true
a = Dog{}
fmt.Println(a == nil) // false
fmt.Println(a.Sound())
}複数のインターフェースを満たす
1つの型で複数のインターフェースを同時に満たせます:
package main
import "fmt"
type Reader interface{ Read() string }
type Writer interface{ Write(string) }
type ReadWriter interface{ Reader; Writer }
type File struct{ content string }
func (f *File) Read() string { return f.content }
func (f *File) Write(s string) { f.content = s }
func main() {
var rw ReadWriter = &File{}
rw.Write("hello")
fmt.Println(rw.Read())
}インターフェースの代入
より広いインターフェースには、より限定的な具体値を保持できます。インターフェース型の間で代入するには、具体的な型が両方のインターフェースを満たしている必要があります:
package main
import "fmt"
type Stringer interface{ String() string }
type Point struct{ X, Y int }
func (p Point) String() string { return fmt.Sprintf("(%d,%d)", p.X, p.Y) }
func main() {
var s Stringer = Point{3, 4}
fmt.Println(s.String())
}nilインターフェースの落とし穴
nilの具体値を保持するnilではないインターフェースは、nilと等しくありません:
package main
import "fmt"
type MyErr struct{}
func (e *MyErr) Error() string { return "oops" }
func bad() error {
var e *MyErr // nil pointer
return e // returns non-nil interface!
}
func main() {
err := bad()
fmt.Println(err == nil) // false — common gotcha
}インターフェースでテスト可能性を高める
依存関係をインターフェースとして定義すると、テストで実際の実装をモックに置き換えられます:
package main
import "fmt"
type EmailSender interface{ Send(to, body string) error }
type MockSender struct{ Sent []string }
func (m *MockSender) Send(to, body string) error {
m.Sent = append(m.Sent, to)
return nil
}
func notify(s EmailSender, addr string) { s.Send(addr, "hello") }
func main() {
mock := &MockSender{}
notify(mock, "a@b.com")
fmt.Println(mock.Sent) // [a@b.com]
}インターフェースを受け取り、構造体を返す
Goのベストプラクティスの1つは、関数パラメーターにはインターフェース(柔軟性のため)を使い、戻り値の型には具体的な型(呼び出し元が受け取るものを明確にするため)を使うことです:
package main
type Logger interface{ Log(string) }
type FileLogger struct{}
func (f *FileLogger) Log(s string) {}
func NewFileLogger() *FileLogger { // returns concrete
return &FileLogger{}
}
func process(l Logger) {} // accepts interface
func main() { process(NewFileLogger()) }インターフェースは小さく保つ
Goの標準ライブラリでは、小さなインターフェースが重視されています。io.Readerはメソッドを1つ、io.Writerもメソッドを1つ持ちます。小さなインターフェースは組み合わせやすく、モックも作りやすくなります。
確認問題
型は、インターフェースを実装することを宣言する必要がありますか?
まとめ: インターフェース
重要なポイント:
- インターフェースはデータではなく振る舞いを定義します
- インターフェースの充足は暗黙的で、
implementsキーワードはありません - 空のインターフェース(
any)はすべての型を受け入れます - nilインターフェースの落とし穴に注意します
- インターフェースは小さく、目的を絞って保ちます
練習課題
Save(key, value string) errorとLoad(key string) (string, error)を持つStorageインターフェースを定義してください。マップを基盤とするMemStorageで実装し、テストしてください。
よくある質問
「インターフェースの定義と実装」レッスンは無料ですか?
はい。「インターフェースの定義と実装」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「インターフェースの定義と実装」で何を学びますか?
暗黙的な実装と空のインターフェース ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「インターフェースの定義と実装」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。