Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
マスター・オブ・
reflectパッケージ II
2016/04/17(日)
@第3回 関西golang勉強会
The Go gopher was designed by Renee French.
The gopher stickers wa...
アジェンダ
■ 自己紹介
■ 基礎編
● reflectパッケージとは?
● Value型とType型
● 変数に値を入れる
● 構造体を触る
■ 応用編
● 任意の型にメソッドを生やしたい
● 任意個のチャネルに対してselectしたい
● ...
自己紹介
KLab株式会社
KLabGames事業本部 エンジニア
@六本木
上田拓也
twitter: @tenntenn
■ 好きな言語
Go, JavaScript, Lua
■ 業務
モバイルオンラインゲームの開発:Unity, Lua...
基礎編
5
reflectパッケージとは?
■ 何ができるのか?
● 実行時に型情報を取得
● 任意の型の変数に値を入れる
● 構造体のフィールドのタグを取得する
■ どこで使われてるの?
● encodingパッケージ
● ORマッパーなど
■ なんで使...
Value型とType型
■ Value型
● 任意の値を表す型
● 値への操作をメソッドで提供
● reflect.ValueOf()で取得できる
■ Type型
● 任意の型を表す型
● 型に関する操作をメソッドで提供
● reflect....
変数に値を入れる
基礎編
8
var n int
fmt.Println(n) // 0
vp := reflect.ValueOf(&n)
v := vp.Elem()
if v.CanSet() {
v.SetInt(100)
}
fmt....
構造体を触る
基礎編
9
s := struct{
A string `k:"v"`; b int
}{"a", 1}
v := reflect.ValueOf(&s).Elem() println(v.
FieldByName("A").Ca...
応用編
10
任意の型にメソッドを生やしたい 1
■ メソッド
● パッケージ内の型をレシーバにできる
● メソッド値として扱える
応用編
11
type MyInt int
func (n MyInt) Int() int {
return int(n)
...
任意の型にメソッドを生やしたい 2
■ reflectで関数を作る
● MakeFuncを使う
応用編
12
func Compose(f, g, fptr interface{}) {
fv, gv := reflect.ValueOf(f)...
任意の型にメソッドを生やしたい 3
■ メソッドのValue値へ値を設定できるか?
● できない!
応用編
13
n := MyInt(100)
v := reflect.ValueOf(&n).Elem()
fv := v.MethodByN...
任意の型にメソッドを生やしたい 4
■ メソッドの振る舞いを動的に変える
● インタフェースを埋め込む
応用編
14
type Hoge interface{M()}
type fuga struct {Hoge}
func (f fuga) ...
任意個のチャネルに対してselectしたい 1
■ select
● 複数チャネルの受信/送信を行う
● コンパイル時に対象のチャネル数は決定
応用編
15
select {
case n := <-ch1:
println(n)
case c...
任意個のチャネルに対してselectしたい 2
■ reflectでselectする
● reflect.Selectを使う
● 任意の個数のSelectCaseを渡せる
応用編
16
ch1, ch2 := make(chan int), m...
実行時に任意の型を作りたい 1
■ Type型
● 実はインタフェース
● reflect.New(typ Type) Value
○ 任意の型の値を生成できる
応用編
17
type MyType struct {reflect.Type}
...
実行時に任意の型を作りたい 2
■ そんなに現実は甘くない
応用編
18
$ go run main.go
bool
panic: interface conversion: reflect.Type is
main.MyType, not *...
実行時に任意の型を作りたい 3
■ Type型の実態
● *rtype型がType型を実装している
■ New関数の実装
応用編
19
func New(typ Type) Value {
if typ == nil {
panic("refl...
まとめ
■ reflectパッケージは楽しくて強力
● 動的に色々できる
○ StructTagの取得
○ 任意個のSelectCase
■ 使うときは慎重に
● reflectしかできないこと?
● 自動コード生成でどうにかならない?
● イ...
マスター・オブ・reflectパッケージ II
マスター・オブ・reflectパッケージ II
Upcoming SlideShare
Loading in …5
×

マスター・オブ・reflectパッケージ II

1,676 views

Published on

第3回 関西golang勉強会で発表した資料です。

Published in: Technology
  • Be the first to comment

マスター・オブ・reflectパッケージ II

  1. 1. マスター・オブ・ reflectパッケージ II 2016/04/17(日) @第3回 関西golang勉強会 The Go gopher was designed by Renee French. The gopher stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license. 参考:マスター・オブ・reflectパッケージ Go研 Vol.8
  2. 2. アジェンダ ■ 自己紹介 ■ 基礎編 ● reflectパッケージとは? ● Value型とType型 ● 変数に値を入れる ● 構造体を触る ■ 応用編 ● 任意の型にメソッドを生やしたい ● 任意個のチャネルに対してselectしたい ● 実行時に任意の型を作りたい ■ まとめ 2
  3. 3. 自己紹介 KLab株式会社 KLabGames事業本部 エンジニア @六本木 上田拓也 twitter: @tenntenn ■ 好きな言語 Go, JavaScript, Lua ■ 業務 モバイルオンラインゲームの開発:Unity, Lua ■ 最近はまってること 英会話 3
  4. 4. 基礎編 5
  5. 5. reflectパッケージとは? ■ 何ができるのか? ● 実行時に型情報を取得 ● 任意の型の変数に値を入れる ● 構造体のフィールドのタグを取得する ■ どこで使われてるの? ● encodingパッケージ ● ORマッパーなど ■ なんで使うの? ● ジェネリクスがない ● ただ、ただ楽しい!!! 基礎編 6
  6. 6. Value型とType型 ■ Value型 ● 任意の値を表す型 ● 値への操作をメソッドで提供 ● reflect.ValueOf()で取得できる ■ Type型 ● 任意の型を表す型 ● 型に関する操作をメソッドで提供 ● reflect.TypeOf()で取得できる 基礎編 7
  7. 7. 変数に値を入れる 基礎編 8 var n int fmt.Println(n) // 0 vp := reflect.ValueOf(&n) v := vp.Elem() if v.CanSet() { v.SetInt(100) } fmt.Println(n) // 100 http://play.golang.org/p/HkJPjQsP8o
  8. 8. 構造体を触る 基礎編 9 s := struct{ A string `k:"v"`; b int }{"a", 1} v := reflect.ValueOf(&s).Elem() println(v. FieldByName("A").CanSet()) println(v.FieldByName("b").CanSet()) f1, ok := v.Type().FieldByName("A") println(ok, f1.PkgPath, f1.Tag.Get("k")) f2, _ := v.Type().FieldByName("b") println(f2.PkgPath) http://play.golang.org/p/NkwP3KSjDu
  9. 9. 応用編 10
  10. 10. 任意の型にメソッドを生やしたい 1 ■ メソッド ● パッケージ内の型をレシーバにできる ● メソッド値として扱える 応用編 11 type MyInt int func (n MyInt) Int() int { return int(n) } func main() { f := MyInt(100).Int println(f()) } http://play.golang.org/p/b4p60PpJtj
  11. 11. 任意の型にメソッドを生やしたい 2 ■ reflectで関数を作る ● MakeFuncを使う 応用編 12 func Compose(f, g, fptr interface{}) { fv, gv := reflect.ValueOf(f), reflect.ValueOf(g) fgv := func(in []reflect.Value) []reflect.Value { return gv.Call(fv.Call(in)) } out := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(out.Type(), fgv) out.Set(v) } http://play.golang.org/p/_bNy3H2575
  12. 12. 任意の型にメソッドを生やしたい 3 ■ メソッドのValue値へ値を設定できるか? ● できない! 応用編 13 n := MyInt(100) v := reflect.ValueOf(&n).Elem() fv := v.MethodByName("Int") // false println(fv.CanSet()) http://play.golang.org/p/yXFpnucbPw
  13. 13. 任意の型にメソッドを生やしたい 4 ■ メソッドの振る舞いを動的に変える ● インタフェースを埋め込む 応用編 14 type Hoge interface{M()} type fuga struct {Hoge} func (f fuga) M() { fmt.Println("Hi") f.Hoge.M() // 元のメソッドを呼ぶ } func HiHoge(h Hoge) Hoge { return fuga{h} // 構造体作る } Mの振る舞いを変える
  14. 14. 任意個のチャネルに対してselectしたい 1 ■ select ● 複数チャネルの受信/送信を行う ● コンパイル時に対象のチャネル数は決定 応用編 15 select { case n := <-ch1: println(n) case ch2 <- 100: default: println("Defualt") }
  15. 15. 任意個のチャネルに対してselectしたい 2 ■ reflectでselectする ● reflect.Selectを使う ● 任意の個数のSelectCaseを渡せる 応用編 16 ch1, ch2 := make(chan int), make(chan int) go func() {ch1 <- 100}() go func() {<-ch2}() i, v, ok := reflect.Select([]reflect.SelectCase{ // case: <-ch1 {reflect.SelectRecv, reflect.ValueOf(ch1), reflect.ValueOf(nil)}, // case: ch2 <- 100 {reflect.SelectSend, reflect.ValueOf(ch2), reflect.ValueOf(100)}, // default: {reflect.SelectDefault, reflect.ValueOf(nil), reflect.ValueOf(nil)}, }) fmt.Println(i, v, ok) http://play.golang.org/p/7t3awR7EZC
  16. 16. 実行時に任意の型を作りたい 1 ■ Type型 ● 実はインタフェース ● reflect.New(typ Type) Value ○ 任意の型の値を生成できる 応用編 17 type MyType struct {reflect.Type} func (typ MyType) Kind() reflect.Kind { return reflect.Bool } t:= MyType{reflect.TypeOf(0)} println(t.Kind()) // bool v := reflect.New(t) Kindの挙動だけ変える
  17. 17. 実行時に任意の型を作りたい 2 ■ そんなに現実は甘くない 応用編 18 $ go run main.go bool panic: interface conversion: reflect.Type is main.MyType, not *reflect.rtype エクスポートされてない!
  18. 18. 実行時に任意の型を作りたい 3 ■ Type型の実態 ● *rtype型がType型を実装している ■ New関数の実装 応用編 19 func New(typ Type) Value { if typ == nil { panic("reflect: New(nil)") } ptr := unsafe_New(typ.(*rtype)) fl := flag(Ptr) return Value{typ.common().ptrTo(), ptr, fl} } ここでpanicが起きる
  19. 19. まとめ ■ reflectパッケージは楽しくて強力 ● 動的に色々できる ○ StructTagの取得 ○ 任意個のSelectCase ■ 使うときは慎重に ● reflectしかできないこと? ● 自動コード生成でどうにかならない? ● インタフェースで十分では? ● パフォーマンスは? 20

×