汎用的な関数を作りたいときにinterface{}
型を引数にしてswitch
で処理を書くことがあります。
忘れないうちに要点メモ。switchの以下の要素を使います。
- Type switch:インターフェースの型分岐
- Multiple cases:複数ケースの処理
golangのswitch
は基本break
はいりません(case内のif
内で中断などは可能)。
該当ケースがあればその中の処理だけをするので、逆に該当以下の処理を全部やらせたい場合にはfallthrough
キーワードを使います。
この辺の動作は公式wikiが一番わかりやすかったです。
適当なケース分けをしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
type mytype struct { } func test1(i interface{}) { switch i.(type) { case int, float32, float64: fmt.Println("this is int or float") case string: fmt.Println("this is string") default: fmt.Println("other type") } } func main() { test1(21) test1(3.14) test1("hello") test1(true) test1(mytype{}) } /* > go run .\main.go this is int or float this is int or float this is string other type other type */ |
interface.(type)を一時変数にしてcase内で実値として使えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
func test2(i interface{}) { switch v := i.(type) { case int, float32, float64: fmt.Printf("%v is %T\n", v, v) case string, mytype: fmt.Printf("%v is %T\n", v, v) default: fmt.Printf("other type %T\n", v) } } /* > go run .\main.go 21 is int 3.14 is float64 hello is string other type bool {} is main.mytype */ |
このときMultiple casesだと値にかかわる操作をできません。
エラー:invalid operation: v + 1 (mismatched types interface {} and int)
単体caseであれば型に沿った操作が可能です。
gormを使ったDB操作を1つにまとめるなんてことも可能です。
こんな横着を見たことはないですが。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
func (m Repository) Create(record interface{}) { switch r := record.(type) { case *Task, *Work, *Remind: log.Printf("CREATE %T", r) db.AutoMigrate(&r) db.Create(&r) default: log.Printf("CREATE not support %T\n", r) } } ... func main() { repo := ctrl.NewRepository() task := ctrl.Task{ID: 15, Text: "test"} repo.Create(&task) } |
何かしら汎用メソッドを作るときに役立ちそうなので覚えておきます。