LoginSignup
6
3

More than 5 years have passed since last update.

しばらく書かないと忘れそうなGoのインターフェースについて、未来の自分へのメモ

Last updated at Posted at 2018-07-30

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"

参考

A Tour of Go
golang.jp

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3