golang - Go言語における埋め込みによるインタフェースの部分実装パターン - Qiita [キータ]golang はインタフェースがマッチしているかどうかにより処理を切り分けられる。
http://qiita.com/tenntenn/items/e04441a40aeb9c31dbaf
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 というメソッドを持ったインタフェース Execer を用意して
Exec(query string, args []Value) (Result, error)
}
if execer, ok := dc.ci.(driver.Execer); ok {Execer にアサーション可能な場合だけ特別な処理を行う、という事をやっています。
}
C/C++ の様に依存ライブラリの特定バージョン以降でメソッドがあったり無かったりという呪縛から解き放たれる訳です。
これがリフレクション無しに出来るのは便利ですね。