インターフェース

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

行動こうどうる、身分みぶんない

  1. オブジェクトが必要ひつようなメソッド/行動こうどう実行じっこうできれば、使用しよう可能かのう
  2. 明示的めいじてき継承けいしょうやインターフェース実装じっそう不要ふよう
  3. なにができるか」に注目ちゅうもくし、「なんであるか」ではない

この設計せっけいはプログラムを柔軟じゅうなんにするが、実行時じっこうじエラーに注意ちゅうい必要ひつよう

// 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+ では anyinterface{} のエイリアスとして使用しよう可能かのう

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")
}

関連トピック