インターフェース
Go 言語のインターフェース:Duck Typing、メソッド集合。
Interface
インターフェースはメソッド集合の設計図。
- メソッドの集合を指定するが、実装しない
- 変数を宣言しない
- メソッドを定義しない
type <interface_name> interface {
// Method signatures
}基本例
type Speaker interface {
Speak() string
}
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return "Woof!"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return "Meow!"
}
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Woof!
MakeSound(cat) // Meow!
}Duck Typing
行動を見る、身分を見ない
- オブジェクトが必要なメソッド/行動を実行できれば、使用可能
- 明示的な継承やインターフェース実装は不要
- 「何ができるか」に注目し、「何であるか」ではない
この設計はプログラムを柔軟にするが、実行時エラーに注意が必要。
// Write メソッドを持つ任意の型は io.Writer を満たす
type Writer interface {
Write(p []byte) (n int, err error)
}
// カスタム型
type ConsoleWriter struct{}
func (cw ConsoleWriter) Write(p []byte) (n int, err error) {
return fmt.Println(string(p))
}
// io.Writer として使用可能
var w io.Writer = ConsoleWriter{}Empty Interface
空インターフェース interface{} は任意の型の値を保持できる。
func PrintAnything(v interface{}) {
fmt.Printf("Type: %T, Value: %v\n", v, v)
}
func main() {
PrintAnything(42)
PrintAnything("hello")
PrintAnything(true)
PrintAnything([]int{1, 2, 3})
}Go 1.18+ では
any を interface{} のエイリアスとして使用可能。Type Assertion
型アサーションはインターフェースから具体的な型を取得するために使用。
var i interface{} = "hello"
// 基本アサーション(失敗すると panic)
s := i.(string)
// 安全なアサーション(推奨)
s, ok := i.(string)
if ok {
fmt.Println("String:", s)
}
// アサーション失敗でも panic しない
n, ok := i.(int)
if !ok {
fmt.Println("Not an int")
}Type Switch
複数の可能な型を処理するために使用。
func describe(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("Integer: %d\n", v*2)
case string:
fmt.Printf("String: %q (len=%d)\n", v, len(v))
case bool:
fmt.Printf("Boolean: %t\n", v)
case []int:
fmt.Printf("Slice of int: %v\n", v)
default:
fmt.Printf("Unknown type: %T\n", v)
}
}Interface Composition
インターフェースは他のインターフェースを組み合わせることができる。
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
// インターフェースの組み合わせ
type ReadWriter interface {
Reader
Writer
}Type List
Ordered Type:<, <=, >, >= 演算子もサポート。
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64 |
~string
}
func Min[T Ordered](a, b T) T {
if a < b {
return a
}
return b
}一般的なインターフェース
Stringer
type Stringer interface {
String() string
}
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%s (%d years old)", p.Name, p.Age)
}Error
type error interface {
Error() string
}
type MyError struct {
Code int
Message string
}
func (e MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}nil
error 位置で nil を返すとエラーがないことを示す。
func doSomething() error {
// 成功時は nil を返す
return nil
}
// インターフェース値が nil の場合
var s Speaker // nil
if s == nil {
fmt.Println("s is nil")
}インターフェース値は型と値の 2 つの部分を含む。両方が nil の場合のみ、インターフェース値は nil と等しい。
var p *Dog = nil
var s Speaker = p
// s != nil(型は nil ではない)
if s == nil {
fmt.Println("this won't print")
}