[Go 再学習] Go の interface を理解する
Go の再学習をしている最中なのですが、学習当初 Go Interface は「なんとなく分かるが使いこなせない」という感覚を持っていました。自分のコードでも使っているのですが、どのようなパターンで使えるのかを網羅的には知っていない状態だったのでこれを機に調べてみました。この記事では基本的な定義から実務でよく登場するパターンまでをサンプルコードと共に整理しました。 コードは以下のレポジトリにあります。 https://github.com/jedipunkz/go-tips interface とは interface はメソッドのシグネチャの集合を定義する型です。ある型が interface に定義されたメソッドをすべて持っていれば、自動的にその interface を満たします。 この設計により、既存のコードを変更せずに後から interface に適合させることができます。 パターン1: 基本的な interface 最もシンプルな interface の定義と利用です。Shape interface を定義し、Circle と Rectangle がそれを実装します。 使い所 図形の面積や周長を計算する処理を書く場合、Circle や Rectangle ごとに別々の関数を用意すると、新しい図形が増えるたびに呼び出し側の修正が必要になります。Shape interface を定義して関数が Shape を受け取るようにすると、新しい図形を追加しても既存の関数はそのまま使え、拡張が容易になります。 package main import ( "fmt" "math" ) // Shape インターフェースを定義する // メソッドセットを持つ型はこのインターフェースを満たす type Shape interface { Area() float64 Perimeter() float64 } type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius } func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.Radius } type Rectangle struct { Width, Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } func (r Rectangle) Perimeter() float64 { return 2 * (r.Width + r.Height) } // インターフェース型を引数に取ることで、どの Shape 実装でも受け付ける func printShapeInfo(s Shape) { fmt.Printf("面積: %.2f, 周長: %.2f\n", s.Area(), s.Perimeter()) } func main() { c := Circle{Radius: 5} r := Rectangle{Width: 4, Height: 6} fmt.Print("Circle: ") printShapeInfo(c) fmt.Print("Rectangle: ") printShapeInfo(r) } printShapeInfo は Shape を受け取るだけで、Circle か Rectangle かを意識しません。新たに Triangle を追加したとしても、Area() と Perimeter() を実装するだけで既存コードの変更なく動きます。 ...