share facebook facebook twitter menu hatena pocket slack

2018.08.20 MON

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

恩田 大輝

WRITTEN BY 恩田 大輝

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

元記事はこちら

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

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。