Go始めた時に「ん?」って思ったインターフェースについての私的です。
未来の僕が困らないためにここに記しておきます。
golangのインターフェース
馴染みのあるインターフェース
type Unk interface{
out()
call()
}
type MyUnk struct {
name string
}
func (u *MyUnk) out() {
fmt.Println(name + "ちゃん出た")
}
func (u *MyUnk) call() {
fmt.Println("虫を呼ぶよ")
}
// A Tour of Go: https://go-tour-jp.appspot.com/methods/9
// interface(インタフェース)型は、メソッドのシグニチャの集まりで定義します。
// そのメソッドの集まりを実装した値を、interface型の変数へ持たせることができます。
個人的に「ん?」となったインターフェース型
var i interface{}
i = 20 // reflect.TypeOf(i) String
i = "unk" // reflect.TypeOf(i) int
i = []byte("unk") // reflect.TypeOf(i) []uint8
i = map[string]interface{}{
"Type": "unk",
"State": "oops",
} // reflect.TypeOf(i) map[string]interface {}
// A Tour of Go: https://go-tour-jp.appspot.com/methods/14
// 空のインターフェースは、任意の型の値を保持できます。 (全ての型は、少なくともゼロ個のメソッドを実装しています。)
interface型はなんでもおkらしい
全ての型は、0個のメソッドを持っているので、との事。
type Empty interface{
}
試しに
func main() {
var i interface{}
i = 20
Otamesi(i) // int
}
func Otamesi(v interface{}) {
fmt.Println(v)
fmt.Println(reflect.TypeOf(v))
}
// なんでもおk!
型アサーションで良い感じに出来る
vendor以下に潜っていて構造体でinterfaceの値を持っているものなど、必要な値を抽出したい時によくお世話になりました。
// assertion
str, ok := interface.(string)
int, ok := interface.(int)
map, ok := interface.(map[string]interface{})
interfaceはキャスト出来ない。
// cast
str := string(int) // ok
str := string(interface) // panic
型判定
多言語でのswitch文とちょっと違う。
switch v := i.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n",
}
// A Tour of Go: https://go-tour-jp.appspot.com/methods/16
Goのswitchは条件にヒットした場合、そのスコープ内の処理を終えた後、自動でbreakします。
記事中に何度も出てきてるけどよくお世話になった連想配列シリーズ
unk := map[string]interface{}{
"name": "smith",
}
jsonの取り扱い
toJson
unk := &Unk{
Type: "secret",
State: "new",
}
unkBlob, _ := json.Marshal(unk)
fmt.Println(unkBlob)
fmt.Println(string(unkBlob))
// {
// "Type": "secret",
// "State": "new"
// }
//
toStructType
blob := []byte(`{"Type": "secret", "State": "new"}`)
var unk Unk
err := json.Unmarshal(blob, &unk)
if err != nil {
fmt.Println(err)
}
fmt.Println(&unk)
//
// &{secret new}
//
toInterface
blob := []byte(`{"Type": "secret", "State": "new"}`)
var unk interface{}
err := json.Unmarshal(blob, &unk)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%#v\n", &unk)
// (*interface {})(0xc42000e220)
fmt.Printf("%#v\n", unk)
// map[string]interface {}{"Type":"secret", "State":"new"}
fmt.Println(unk["Type"]) // panic
// ここでアサーション
fmt.Println(unk.(map[string]interface{})["Type"])
// "secret"