2013/09/19

Recent entries from same category

  1. TensorFlow Lite の Go binding を書いた。
  2. Lint ツールを Language Server に対応させるコマンド efm-langserver 作った。
  3. gocode やめます(そして Language Server へ)
  4. Golang だけでやる機械学習と画像分類
  5. 書評「Go言語による並行処理」

golang - Go言語における埋め込みによるインタフェースの部分実装パターン - Qiita [キータ]
http://qiita.com/tenntenn/items/e04441a40aeb9c31dbaf
golang はインタフェースがマッチしているかどうかにより処理を切り分けられる。
package main

import "fmt"

type Person struct {
    FirstName string
    LastName  string
}

func (p *Person) Name() string {
    return p.FirstName + " " + p.LastName
}

func main() {
    person := &Person{"Taro""Yamada"}
    fmt.Println(person.Name())
}
メソッドを保持しているのであれば、インタフェースにアサーション出来る。
package main

import "fmt"

type Person struct {
    FirstName string
    LastName  string
}

func (p *Person) Name() string {
    return p.FirstName + " " + p.LastName
}

type Named interface {
    Name() string
}

func printName(named Named) {
    fmt.Println(named.Name())
}

func main() {
    person := &Person{"Tarou""Yamada"}
    printName(person)
}
そして実は型がマッチしているかを確認する事も出来る。interface{} にキャストした後に指定のインタフェースで型アサーションを行う。その際に戻り値の2つめにアサーションが成功したかどうかが返される。
package main

import "fmt"

type Person struct {
    FirstName string
    LastName  string
}

func (p *Person) Name() string {
    return p.FirstName + " " + p.LastName
}

type Named interface {
    Name() string
}

// パーさんは Name メソッドを持たない
type Persan struct {
    FirstName string
    LastName  string
}

func printName(named Named) {
    fmt.Println(named.Name())
}

func main() {
    person := &Person{"Tarou""Yamada"}
    named, ok := interface{}(person).(Named)
    if ok {
        printName(named)
    } else {
        fmt.Println("Person is not Named intreface")
    }

    persan := &Persan{"Tarou""Yamada"}
    named, ok = interface{}(persan).(Named)
    if ok {
        printName(named)
    } else {
        fmt.Println("Persan is not Named intreface")
    }
}
つまり例えば、ライブラリやドライバが新しいメソッドに対応しているかどうか、と言った事を動的に確認出来る様になります。
この手法はオフィシャルパッケージの database/sql でも使われており、各ドライバが指定のインタフェースを実装しているかどうかを確認しています。
type Execer interface {
    Exec(query string, args []Value) (Result, error)
}
Exec というメソッドを持ったインタフェース Execer を用意して
if execer, ok := dc.ci.(driver.Execer); ok {
}
Execer にアサーション可能な場合だけ特別な処理を行う、という事をやっています。
C/C++ の様に依存ライブラリの特定バージョン以降でメソッドがあったり無かったりという呪縛から解き放たれる訳です。
これがリフレクション無しに出来るのは便利ですね。

blog comments powered by Disqus