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"