Gunosy.go#7 reflect

1,044 views
819 views

Published on

These slides are for Gunosy.go #7.

http://gunosygo.connpass.com/event/7643/

Published in: Engineering
0 Comments
9 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,044
On SlideShare
0
From Embeds
0
Number of Embeds
68
Actions
Shares
0
Downloads
11
Comments
0
Likes
9
Embeds 0
No embeds

No notes for slide

Gunosy.go#7 reflect

  1. 1. reflect&package @takufukushima
  2. 2. What%is%"reflec&on"? Reflec%on(in(compu%ng(is(the(ability(of(a(program(to( examine(its(own(structure,(par%cularly(through(types;( it's(a(form(of(metaprogramming.(It's(also(a(great( source(of(confusion. —"h$p://blog.golang.org/laws2of2reflec7on
  3. 3. Agenda • Inside(of(Interfaces • The(Laws(of(Reflec5on • reflect(Package
  4. 4. Inside'of'Interfaces
  5. 5. Types&and&interfaces:&Types type MyInt int var i int var j MyInt // You can't assign j to i without conversion. i = j // ERROR!
  6. 6. Types&and&interfaces:&Interfaces // io.Reader is the interface that wraps the // basic Read method. type Reader interface { Read(p []byte) (n int, err error) } var r io.Reader r = os.Stdin r = bufio.NewReader(r) r = new(bytes.Buffer)
  7. 7. Interfaces*are*sta+cally*checked interface {} Go's%interfaces—sta/c,%checked%at%compile%/me,% dynamic%when%asked%for—are,%for%me,%the%most% exci/ng%part%of%Go%from%a%language%design%point%of% view.%If%I%could%export%one%feature%of%Go%into%other% languages,%it%would%be%interfaces. —"Russ"Cox,"Go"Data"Structures:"Interfaces h"p://research.swtch.com/interfaces
  8. 8. Example:)Stringer)interface type Stringer interface { String() string } func ToString(any interface{}) string { if v, ok := any.(Stringer); ok { return v.String() } switch v := any.(type) { case int: return strconv.Itoa(v) case float: return strconv.Ftoa(v, 'g', -1) } return "???" }
  9. 9. Example:)Binary)has)String) method type Binary uint64 // Binary implements Stringer interface func (i Binary) String() string { return strconv.Uitob64(i.Get(), 2) } func (i Binary) Get() uint64 { return uint64(i) }
  10. 10. itable:"an"interface"table b := Binary(200)
  11. 11. Behind'the'scene'of'the'method' invoca0on b := Binary(200) s := Stringer(b) // var s Stringer = b makes a copy of b var c uint64 = b // This makes a copy of b s.String() // tab->fun[0](s.data) in C
  12. 12. Compu&ng)the)itable Precompu)ng,all,possible,itables,costs,a,lot.,So, they're,computed,at,run)me.,See,go/src/pkg/ runtime/iface.goc. • The%compiler%generates%a%type%descrip4on% structure%for%each%concreate%type • The%compiler%generates%a%(different)%type% descrip4on%structure%for%each%interface%type • The%interface%run4me%computes%the%itable%looking% for%each%method%tables
  13. 13. Op#miza#on*of*compu#ng*the*itable • Cache'the'itable • Sort'two'method'tables'(for'the'concrete'types'and' interface'types)'and'walking'them'simultaneously • From'O(ni%*%nt)'to'O(ni%+%nt)
  14. 14. Memory'Op*miza*on:'Empty'interface
  15. 15. Memory'Op*miza*on:'Small'enough'value
  16. 16. Memory'Op*miza*on:'Combina*on'of'the'two' cases
  17. 17. Method'Loookup'Performance • In$Smalltalk+ish$way,$the$method$lookup$happens$ every$9me$with$maybe$caching • In$Go,$a>er$the$computa9on$of$itable$it$is$a$couple$ of$memory$fetches$and$a$single$indirect$call$ instruc9on var any interface{} // initialized elsewhere s := any.(Stringer) // dynamic conversion for i := 0; i < 100; i++ { fmt.Println(s.String()) }
  18. 18. The$Laws$of$Reflec.on
  19. 19. The$Laws$of$Reflec.on$by$Rob$Pike h"p://blog.golang.org/laws0of0reflec5onn 1. Reflec'on*goes*from*interface*value*to*reflec'on* object 2. Reflec'on*goes*from*reflec'on*object*to*interface* value 3. To*modify*a*reflec'on*object,*the*value*must*be* se?able
  20. 20. 1.#Reflec(on#goes#from#interface# value#to#reflec(on#object var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("type:", v.Type()) fmt.Println("kind is float64:", v.Kind() == reflect.Float64) fmt.Println("value:", v.Float()) pritns type: float64 kind is float64: true value: 3.4
  21. 21. Type!and!Kind var x uint8 = 'x' v := reflect.ValueOf(x) fmt.Println("type:", v.Type()) // uint8. fmt.Println("kind is uint8: ", v.Kind() == reflect.Uint8) // true. x = uint8(v.Uint()) // v.Uint returns a uint64. type MyInt int var x MyInt = 7 v := reflect.ValueOf(x) fmt.Println("kind is Int: ", v.Kind() == reflect.Int) // true.
  22. 22. 2.#Reflec(on#goes#from#reflec(on# object#to#interface#value // Interface returns v's value as an interface{}. // func (v Value) Interface() interface{} y := v.Interface().(float64) // y will have type float64 fmt.Println(y) fmt.Printf("value is %7.1en", v.Interface()) // 3.4e+00 In#short,#the#Interface#method#is#the#inverse#of#the# ValueOf#func6on,#except#that#its#result#is#always#of# sta6c#type#interface{}. Reitera6ng:#Reflec6on#goes#from#interface#values#to# reflec6on#objects#and#back#again.
  23. 23. 3.#To#modify#a#reflec0on#object,#the# value#must#be#se;able var x float64 = 3.4 v := reflect.ValueOf(x) v.SetFloat(7.1) // Error: will panic. // panic: reflect.Value.SetFloat using unaddressable value var x float64 = 3.4 v := reflect.ValueOf(x) fmt.Println("settability of v:", v.CanSet()) // settability of v: false What%is%"se$ability"?
  24. 24. Se#ability*is*determined*by*whether*the* reflec4on*object*holds*the*original*item. var x float64 = 3.4 // We're passing the copy of x here. v := reflect.ValueOf(x) // Think about the difference between f(x) and f(&x). // v.SetFloat(7.1) updates the copied value inside the // reflection value. So#then,#how#can#we#modify#the#reflec3on#value?
  25. 25. "Use%the%pointer,%Luke." var x float64 = 3.4 p := reflect.ValueOf(&x) // Note: take the address of x. fmt.Println("type of p:", p.Type()) // type of p: *float64 fmt.Println("settability of p:", p.CanSet()) // settability of p: false v := p.Elem() fmt.Println("settability of v:", v.CanSet()) // settability of v: true v.SetFloat(7.1) fmt.Println(v.Interface()) // 7.1 fmt.Println(x) // 7.1
  26. 26. Modifying)Structs type T struct { A int // Only exported fields are settable. B string } t := T{23, "skidoo"} s := reflect.ValueOf(&t).Elem() typeOfT := s.Type() for i := 0; i < s.NumField(); i++ { f := s.Field(i) fmt.Printf("%d: %s %s = %vn", i, typeOfT.Field(i).Name, f.Type(), f.Interface()) } // "0: A int = 23" and "1: B string = skidoo" s.Field(0).SetInt(77) s.Field(1).SetString("Sunset Strip") fmt.Println("t is now", t) // t is now {77 Sunset Strip}
  27. 27. Here$again$are$the$laws$of$reflec2on: • Reflec&on)goes)from)interface)value)to)reflec&on) object • Reflec&on)goes)from)reflec&on)object)to)interface) value • To)modify)a)reflec&on)object,)the)value)must)be) se<able
  28. 28. reflect!Package
  29. 29. Constants'and'u*lity'func*ons const ( SelectSend // case Chan <- Send SelectRecv // case <-Chan: SelectDefault // default ) func Copy(dst, src Value) int // Recursive comparison; []T{} != nil func DeepEqual(a1, a2 interface{}) bool func Select(cases []SelectCase) (chosen int, recv Value, recvOK bool)
  30. 30. Kind const ( 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 )
  31. 31. Types type ChanDir // A channel type's direction func (d ChanDir) String() string type Kind // The specific kind of type func (k Kind) String() string type Method // A single method type SelectCase // A single select case type SelectDir // The communication direction type SliceHeader // A slice type StringHeader // A string type StructField // A single field in a struct type StructTag // The tag in a struct field func (tag StructTag) Get(key string) string type Type // A Go type type Value // A Go value type ValueError // Error for Value func (e *ValueError) Error() string
  32. 32. Type!related!func,ons func ChanOf(dir ChanDir, t Type) Type func MapOf(key, elem Type) Type func PtrTo(t Type) Type func SliceOf(t Type) Type func TypeOf(i interface{}) Type
  33. 33. Type!interface type Type interface { Align() int FieldAlign() int Method(int) Method MethodByName(string) (Method, bool) NumMethod() int Name() string PkgPath() string Size() uintptr String() string Kind() Kind Implements(u Type) bool // Check if it implements Type u AssignableTo(u Type) bool ConvertibleTo(u Type) bool ...
  34. 34. Type!interface ... Bits() int ChanDir() ChanDir // for Chan IsVariadic() bool // for ...argument Elem() Type // for Array, Chan, Map, Ptr, or Slice Field(i int) StructField // for Struct FieldByIndex(index []int) StructField FieldByName(name string) (StructField, bool) FieldByNameFunc(match func(string) bool) (StructField, bool) In(i int) Type // The i'th input of the function Key() Type // for Map Len() int // for Array NumField() int // for Struct NumIn() int // The number of the input of the function NumOut() int // The number of the output of the function Out(i int) Type // The i'th output of the function }
  35. 35. Value!related!func,ons func Append(s Value, x ...Value) Value func AppendSlice(s, t Value) Value func Indirect(v Value) Value func MakeChan(typ Type, buffer int) Value func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value func MakeMap(typ Type) Value func MakeSlice(typ Type, len, cap int) Value func New(typ Type) Value func NewAt(typ Type, p unsafe.Pointer) Value func ValueOf(i interface{}) Value func Zero(typ Type) Value
  36. 36. Value!methods:!Type!and!kind func (v Value) Addr() Value func (v Value) Bool() bool func (v Value) Bytes() []byte func (v Value) Complex() complex128 func (v Value) Float() float64 func (v Value) Int() int64 func (v Value) Interface() (i interface{}) func (v Value) InterfaceData() [2]uintptr func (v Value) Kind() Kind func (v Value) Pointer() uintptr func (v Value) Slice(i, j int) Value func (v Value) Slice3(i, j, k int) Value func (v Value) String() string func (v Value) Type() Type func (v Value) Uint() uint64 func (v Value) UnsafeAddr() uintptr
  37. 37. Value!methods:!Can_,!Is_!and! Overflow_ func (v Value) CanAddr() bool func (v Value) CanInterface() bool func (v Value) CanSet() bool func (v Value) IsNil() bool func (v Value) IsValid() bool func (v Value) OverflowComplex(x complex128) bool func (v Value) OverflowFloat(x float64) bool func (v Value) OverflowInt(x int64) bool func (v Value) OverflowUint(x uint64) bool
  38. 38. Value!methods:!Array,!Slice!and! Map func (v Value) Index(i int) Value func (v Value) Cap() int func (v Value) Len() int func (v Value) MapIndex(key Value) Value func (v Value) MapKeys() []Value
  39. 39. Value!methods:!Channel func (v Value) Recv() (x Value, ok bool) func (v Value) Send(x Value) func (v Value) TryRecv() (x Value, ok bool) func (v Value) TrySend(x Value) bool func (v Value) Close()
  40. 40. Value!methods:!Func.on!and! method func (v Value) Call(in []Value) []Value func (v Value) CallSlice(in []Value) []Value func (v Value) Method(i int) Value func (v Value) MethodByName(name string) Value func (v Value) NumMethod() int
  41. 41. Value!methods:!Field!of!struct func (v Value) Field(i int) Value func (v Value) FieldByIndex(index []int) Value func (v Value) FieldByName(name string) Value func (v Value) FieldByNameFunc(match func(string) bool) Value func (v Value) NumField() int
  42. 42. Value!methods:!Se+ers func (v Value) Set(x Value) func (v Value) SetBool(x bool) func (v Value) SetBytes(x []byte) func (v Value) SetCap(n int) func (v Value) SetComplex(x complex128) func (v Value) SetFloat(x float64) func (v Value) SetInt(x int64) func (v Value) SetLen(n int) func (v Value) SetMapIndex(key, val Value) func (v Value) SetPointer(x unsafe.Pointer) func (v Value) SetString(x string) func (v Value) SetUint(x uint64)
  43. 43. Value!methods:!Value! manipula0on func (v Value) Convert(t Type) Value func (v Value) Elem() Value
  44. 44. Example:)MakeFunc ... func main() { swap := func(in []reflect.Value) []reflect.Value { return []reflect.Value{in[1], in[0]} } makeSwap := func(fptr interface{}) { fn := reflect.ValueOf(fptr).Elem() v := reflect.MakeFunc(fn.Type(), swap) fn.Set(v) } var intSwap func(int, int) (int, int) makeSwap(&intSwap) fmt.Println(intSwap(0, 1)) var floatSwap func(float64, float64) (float64, float64) makeSwap(&floatSwap) fmt.Println(floatSwap(2.72, 3.14)) }
  45. 45. Example:)StructTag package main import ( "fmt" "reflect" ) func main() { type S struct { F string `species:"gopher" color:"blue"` } s := S{} st := reflect.TypeOf(s) field := st.Field(0) fmt.Println(field.Tag.Get("color"), field.Tag.Get("species")) }
  46. 46. Example:)go-martini/martini // Run the http server. Listening on os.GetEnv("PORT") or // 3000 by default. func (m *Martini) Run() { port := os.Getenv("PORT") if port == "" { port = "3000" } host := os.Getenv("HOST") // Dependency injection here. logger := m.Injector.Get( reflect.TypeOf(m.logger)).Interface().(*log.Logger) logger.Printf("listening on %s:%s (%s)n", host, port, Env) logger.Fatalln(http.ListenAndServe(host+":"+port, m)) }
  47. 47. Example:)codegangsta/inject Dependency(Injec+on((DI)(in(Go type injector struct { values map[reflect.Type]reflect.Value parent Injector } // New returns a new Injector. func New() Injector { return &injector{ values: make(map[reflect.Type]reflect.Value), } }
  48. 48. Example:)codegangsta/inject func (i *injector) Map(val interface{}) TypeMapper { i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) return i } func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) return i } func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper { i.values[typ] = val return i }
  49. 49. Example:)codegangsta/inject func (i *injector) Get(t reflect.Type) reflect.Value { val := i.values[t] if val.IsValid() { return val } if t.Kind() == reflect.Interface { for k, v := range i.values { if k.Implements(t) { val = v break } } } if !val.IsValid() && i.parent != nil { val = i.parent.Get(t) } return val }
  50. 50. Use$Negroni,$not$Mar/ni Mar$ni'reflec$on'is'flawed;!"The!real!tradeoff!with! reflec1on!is!one!of!complexity." —"My"Thoughts"on"Mar/ni,"Code"Gangsta h"p://blog.codegangsta.io/blog/2014/05/19/my; thoughts;on;mar>ni/ Gin$is$also$an$alterna,ve.
  51. 51. The$end$of$slides.$Any$ ques1on?
  52. 52. References • The%Go%Blog:%The%Laws%of%Reflec4on • h6p://blog.golang.org/laws<of<reflec4on • Go%Data%Structures • Interfaces%h6p://research.swtch.com/interfaces • Package%reflect • h6p://golang.org/pkg/reflect/ • go<mar4ni/mar4ni • h6ps://github.com/go<mar4ni/mar4ni
  53. 53. References • codegangsta/inject • h/ps://github.com/codegangsta/inject • My8Thoughts8on8Mar;ni,8Code8Gangsta • h/p://blog.codegangsta.io/blog/2014/05/19/ myFthoughtsFonFmar;ni/ • ginFgonic/gin • h/ps://github.com/ginFgonic/gin

×