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パッケージ
2013/10/14 Mon
自己紹介
KLab株式会社
エンジニア

上田拓也
主に使用する言語
趣味:Golang, Java,
仕事:PHP, JavaScript

twitter : @tenntenn
今日話すことは...
● Go研 Vol.8でやったことをまとめたもの
○ https://github.
com/goken/goken/blob/master/goken08-reflect.md
アジェンダ
● なぜ、reflectパッケージを使うのか?
● 実際どこで使われているの?
● Value型とType型
● interface{}とreflectパッケージ
● 構造体のリフレクション
● チャネルのリフレクション
● 関数の...
なぜ、reflectパッケージを使うのか?
動機1: Genericsがない
● こういう事はできない
func foo(in <T>) <T> {//...}
func main() {
n := 100
m := foo(n)
}
動機2:型の情報を取りたい
● 構造体にはタグとしてフィールド情報を埋め込
める → リフレクションで取り出す
type Person struct {
Name string `json:”name”`
Age
}

int

`json:”...
実際どこで使われているの?
encoding/{json, xml, ...}パッケージ
● JSONなどのシリアライズされたものを構造体に
変換する際に使用される
Go言語の構造体:

JSON:

type Person struct {
Name string `j...
{text, html}/templateパッケージ
● HTMLなどに任意の型の値を埋め込むために
使われる
Hello, {{.Name}}!!

Execute

Hello, Gopher!!

テンプレート

出力
データの埋込み

...
Value型とType型
Value型とType型
● Value型
○ 値を表す型
○ 全ての型の値は、reflectパッケージの世界では、Value
型で表される

● Type型
○ 型を表す型
○ 全ての型は、reflectパッケージの世界では、Type型で
表...
Value型の定義
type Value struct {
typ *rtype
// 型
val unsafe.Pointer // 値へのポインタ
flag
// メタ情報
}
Value型の取得とKind
● reflect.ValueOfを使う
v := reflect.Value(100)
● v.Kind()で値の種類がとれる
Invalid Kind = iota
Bool
Int
Int8
Int16
In...
Type型の定義
● インタフェース型
● メソッドやフィールドの情報を取るメソッドがある
● Value型が持っているメソッドに近いものを持っ
ている
Type型の実体
● Type型の実体は*rtype型である
● *rtype型がType型を実装している
type Type interface{
// ….
common() *rtype
uncommon() *uncommonType
...
Type型の取得
● reflect.TypeOf()かValue.Type()で取得できる
t1 := reflect.TypeOf(100)
v := reflect.ValueOf(100)
t2 := v.Type()
● reflec...
interface{}とreflectパッケージ
変数に値を設定する
● ポインタじゃないと設定できない
n := 100
v1 := reflect.ValueOf(n)
fmt.Println(v1.CanSet()) // false=設定
v2 := reflect.ValueOf(&...
変数に値を設定する
n: 100

&n
ValueOf()

Value
(ポインタ)
Elem()

Set

Value
(Int)
interface{}としてポインタを渡す
● interface{}として、任意の型のポインタを受け取
る

func set(p, v interface{}) {
pv := reflect.ValueOf(p) // ポインタ
vv :...
構造体のリフレクション
フィールドの情報を取得する(Value)
type MyStruct struct {
field1 string
field2 MyStruct2
}
type MyStruct2 struct {
field int
}
ms := MyS...
フィールドの情報を取得する(Value)
type MyStruct struct {
field1 string
field2 MyStruct2
}
type MyStruct2 struct {
field int
}
ms := MyS...
Value型から取得したフィールド
● ポインタ経由でないとSetできない
● privateなフィールドにはSetできない
type Hoge struct {
N int
}
func main() {
h := Hoge{10}
hpv ...
フィールドの情報を取得する(Type)
● タグを取得する
type Hoge struct {
N int `json:"n"`
}

type StructTag string

func main() {
h := Hoge{10}
t ...
メソッドの情報の取得
● フィールドと同じようにValue型とType型のオブ
ジェクトから情報がとれる
● Value.Call()でメソッドを呼ぶ事ができる
まとめ
何か値

interface{}
reflect.ValueOf()

Value
.Elem().Set()
Value.XXX()

何かの変数の
ポインタ

Value
reflect.ValueOf()

interface{}
残りは、時間があったらやる
チャネルのリフレクション
チャネルのリフレクション
● reflect.MakeChan
○ チャネルを作れる

● Value.Send()
○ チャネルにデータを送る

● Value.Recv()
○ チャネルからデータを受取る

● Value.TrySend(...
reflect.Select
func Select(cases []SelectCase) (chosen int, recv Value,
recvOK bool)
● 引数
○ cases: caseの配列
● 戻り値
○ chosen:...
SelectCase
type SelectCase struct {
Dir SelectDir // チャネルの方向
Chan Value
Send Value
}

// Valueにしたチャネル
// 送信する値
SelectDir
type SelectDir int
const (
SelectSend

// case Chan <- Send

SelectRecv

// case <-Chan:

SelectDefault // defau...
関数のリフレクション
Callする
f := func(n int) {
fmt.Println(n)
}
fv := reflect.ValueOf(f)
fmt.Println(fv)
// func (v Value) Call(in []Value) []V...
関数の情報をType型から取得する
● Type.NumIn() int
○ 引数の数

● Type.In(i int) Type
○ i番目の引数の型を取得する

● Type.NumOut() int
○ 戻り値の数

● Type.Ou...
関数を作る
func(in []Value) []Value
reflect.MakeFunc()

Value
Elem().Set()

Value

&func(...)...
reflect.ValueOf()
関数を作る - 合成関数を作る
func main() {
f := func(x int) int {
return x * x
}
var g func(x int) int
// 2つの関数を受け取り、第3引数の変数に入れる
Compos...
関数を作る
func Compose(f, g, fptr interface{}) {
fv := reflect.ValueOf(f)
gv := reflect.ValueOf(g)
fgv := func(in []reflect.Va...
まとめ
何か値

interface{}
reflect.ValueOf()

Value
.Elem().Set()
Value.XXX()

何かの変数の
ポインタ

Value
reflect.ValueOf()

interface{}
Upcoming SlideShare
Loading in …5
×

マスター・オブ・Reflectパッケージ

7,908 views

Published on

GoCon 2013 Autumnで発表した資料です。

Published in: Technology

マスター・オブ・Reflectパッケージ

  1. 1. マスター・オブ ・reflectパッケージ 2013/10/14 Mon
  2. 2. 自己紹介 KLab株式会社 エンジニア 上田拓也 主に使用する言語 趣味:Golang, Java, 仕事:PHP, JavaScript twitter : @tenntenn
  3. 3. 今日話すことは... ● Go研 Vol.8でやったことをまとめたもの ○ https://github. com/goken/goken/blob/master/goken08-reflect.md
  4. 4. アジェンダ ● なぜ、reflectパッケージを使うのか? ● 実際どこで使われているの? ● Value型とType型 ● interface{}とreflectパッケージ ● 構造体のリフレクション ● チャネルのリフレクション ● 関数のリフレクション
  5. 5. なぜ、reflectパッケージを使うのか?
  6. 6. 動機1: Genericsがない ● こういう事はできない func foo(in <T>) <T> {//...} func main() { n := 100 m := foo(n) }
  7. 7. 動機2:型の情報を取りたい ● 構造体にはタグとしてフィールド情報を埋め込 める → リフレクションで取り出す type Person struct { Name string `json:”name”` Age } int `json:”age”` →タグ
  8. 8. 実際どこで使われているの?
  9. 9. encoding/{json, xml, ...}パッケージ ● JSONなどのシリアライズされたものを構造体に 変換する際に使用される Go言語の構造体: JSON: type Person struct { Name string `json:”name”` Aget int `json:”age”` } { “name”: “Gopher”, “age”: 4 } タグを使って対応付けがされる!
  10. 10. {text, html}/templateパッケージ ● HTMLなどに任意の型の値を埋め込むために 使われる Hello, {{.Name}}!! Execute Hello, Gopher!! テンプレート 出力 データの埋込み Person { Name: “Gopher”, Age: 4, }
  11. 11. Value型とType型
  12. 12. Value型とType型 ● Value型 ○ 値を表す型 ○ 全ての型の値は、reflectパッケージの世界では、Value 型で表される ● Type型 ○ 型を表す型 ○ 全ての型は、reflectパッケージの世界では、Type型で 表される
  13. 13. Value型の定義 type Value struct { typ *rtype // 型 val unsafe.Pointer // 値へのポインタ flag // メタ情報 }
  14. 14. Value型の取得とKind ● reflect.ValueOfを使う v := reflect.Value(100) ● v.Kind()で値の種類がとれる Invalid Kind = iota Bool Int Int8 Int16 Int32 Int64 Uint Uint8 Uint16 Uint32 Uint64 Uintptr Float32 Float64 Complex64 Complex128 Array Chan Func Interface Map Ptr Slice String Struct UnsafePointer
  15. 15. Type型の定義 ● インタフェース型 ● メソッドやフィールドの情報を取るメソッドがある ● Value型が持っているメソッドに近いものを持っ ている
  16. 16. Type型の実体 ● Type型の実体は*rtype型である ● *rtype型がType型を実装している type Type interface{ // …. common() *rtype uncommon() *uncommonType }
  17. 17. Type型の取得 ● reflect.TypeOf()かValue.Type()で取得できる t1 := reflect.TypeOf(100) v := reflect.ValueOf(100) t2 := v.Type() ● reflect.Newを使えばオブジェクトを作れる typ := reflect.TypeOf(100) obj := reflect.New(typ)
  18. 18. interface{}とreflectパッケージ
  19. 19. 変数に値を設定する ● ポインタじゃないと設定できない n := 100 v1 := reflect.ValueOf(n) fmt.Println(v1.CanSet()) // false=設定 v2 := reflect.ValueOf(&n) v2.Elem().SetInt(200) fmt.Println(n) // 200 Elemでポインタの 指してる先を取得
  20. 20. 変数に値を設定する n: 100 &n ValueOf() Value (ポインタ) Elem() Set Value (Int)
  21. 21. interface{}としてポインタを渡す ● interface{}として、任意の型のポインタを受け取 る func set(p, v interface{}) { pv := reflect.ValueOf(p) // ポインタ vv := reflect.ValueOf(v) // 設定する値 pv.Elem().Set(vv) }
  22. 22. 構造体のリフレクション
  23. 23. フィールドの情報を取得する(Value) type MyStruct struct { field1 string field2 MyStruct2 } type MyStruct2 struct { field int } ms := MyStruct{ // ms.field1 fmt.Println(v.Field(0)) // ms.field2.field fmt.Println(v. FieldByIndex([]int{1, 0})) "str", MyStruct2{100}, } v := reflect.ValueOf(ms) // ms.field1 fmt.Println(v. FieldByName("field1"))
  24. 24. フィールドの情報を取得する(Value) type MyStruct struct { field1 string field2 MyStruct2 } type MyStruct2 struct { field int } ms := MyStruct{ "str", MyStruct2{100}, } v := reflect.ValueOf(ms) f := func(name string) bool { return name == "field1" } fmt.Println(v.FieldByNameFunc (f)) fmt.Println(v.NumField())
  25. 25. Value型から取得したフィールド ● ポインタ経由でないとSetできない ● privateなフィールドにはSetできない type Hoge struct { N int } func main() { h := Hoge{10} hpv := reflect.ValueOf(&h) hpv.Elem().FieldByName("N").SetInt(200) fmt.Println(h) }
  26. 26. フィールドの情報を取得する(Type) ● タグを取得する type Hoge struct { N int `json:"n"` } type StructTag string func main() { h := Hoge{10} t := reflect.TypeOf(h) n, _ := t.FieldByName("N") fmt.Println(n.Tag.Get("json")) }
  27. 27. メソッドの情報の取得 ● フィールドと同じようにValue型とType型のオブ ジェクトから情報がとれる ● Value.Call()でメソッドを呼ぶ事ができる
  28. 28. まとめ 何か値 interface{} reflect.ValueOf() Value .Elem().Set() Value.XXX() 何かの変数の ポインタ Value reflect.ValueOf() interface{}
  29. 29. 残りは、時間があったらやる
  30. 30. チャネルのリフレクション
  31. 31. チャネルのリフレクション ● reflect.MakeChan ○ チャネルを作れる ● Value.Send() ○ チャネルにデータを送る ● Value.Recv() ○ チャネルからデータを受取る ● Value.TrySend(), Value.TryRecv() ○ ブロックしないバージョン ● Value.Len() ○ バッファ内のデータの数 ● Value.Cap() ○ バッファの容量
  32. 32. reflect.Select func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool) ● 引数 ○ cases: caseの配列 ● 戻り値 ○ chosen: 選んだcaseのインデックス ○ recv: 受取ったチャネル ○ recvOK: 受取れたか
  33. 33. SelectCase type SelectCase struct { Dir SelectDir // チャネルの方向 Chan Value Send Value } // Valueにしたチャネル // 送信する値
  34. 34. SelectDir type SelectDir int const ( SelectSend // case Chan <- Send SelectRecv // case <-Chan: SelectDefault // default )
  35. 35. 関数のリフレクション
  36. 36. Callする f := func(n int) { fmt.Println(n) } fv := reflect.ValueOf(f) fmt.Println(fv) // func (v Value) Call(in []Value) []Value fv.Call([]reflect.Value{reflect.ValueOf(100)})
  37. 37. 関数の情報をType型から取得する ● Type.NumIn() int ○ 引数の数 ● Type.In(i int) Type ○ i番目の引数の型を取得する ● Type.NumOut() int ○ 戻り値の数 ● Type.Out(i int) Type ○ i番目の戻り値の型を取得する
  38. 38. 関数を作る func(in []Value) []Value reflect.MakeFunc() Value Elem().Set() Value &func(...)... reflect.ValueOf()
  39. 39. 関数を作る - 合成関数を作る func main() { f := func(x int) int { return x * x } var g func(x int) int // 2つの関数を受け取り、第3引数の変数に入れる Compose(f, f, &g) fmt.Println(g(2)) // 16 }
  40. 40. 関数を作る func Compose(f, g, fptr interface{}) { fv := reflect.ValueOf(f) gv := reflect.ValueOf(g) fgv := func(in []reflect.Value) []reflect.Value { return gv.Call(fv.Call(in)) } fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), fgv) fn.Set(v) }
  41. 41. まとめ 何か値 interface{} reflect.ValueOf() Value .Elem().Set() Value.XXX() 何かの変数の ポインタ Value reflect.ValueOf() interface{}

×