gunosy.go#7 reflect

Post on 06-May-2015

554 Views

Category:

Engineering

6 Downloads

Preview:

Click to see full reader

DESCRIPTION

These slides are for Gunosy.go #7. http://gunosygo.connpass.com/event/7643/

TRANSCRIPT

reflect&package

@takufukushima

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

Agenda• Inside(of(Interfaces

• The(Laws(of(Reflec5on

• reflect(Package

Inside'of'Interfaces

Types&and&interfaces:&Typestype MyInt intvar i intvar j MyInt// You can't assign j to i without conversion.i = j // ERROR!

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.Readerr = os.Stdinr = bufio.NewReader(r)r = new(bytes.Buffer)

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

Example:)Stringer)interfacetype 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 "???"}

Example:)Binary)has)String)method

type Binary uint64

// Binary implements Stringer interfacefunc (i Binary) String() string { return strconv.Uitob64(i.Get(), 2)}

func (i Binary) Get() uint64 { return uint64(i)}

itable:"an"interface"tableb := Binary(200)

Behind'the'scene'of'the'method'invoca0on

b := Binary(200)s := Stringer(b)

// var s Stringer = b makes a copy of bvar c uint64 = b // This makes a copy of b

s.String() // tab->fun[0](s.data) in C

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

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)

Memory'Op*miza*on:'Empty'interface

Memory'Op*miza*on:'Small'enough'value

Memory'Op*miza*on:'Combina*on'of'the'two'cases

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 elsewheres := any.(Stringer) // dynamic conversionfor i := 0; i < 100; i++ { fmt.Println(s.String())}

The$Laws$of$Reflec.on

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

1.#Reflec(on#goes#from#interface#value#to#reflec(on#object

var x float64 = 3.4v := reflect.ValueOf(x)fmt.Println("type:", v.Type())fmt.Println("kind is float64:", v.Kind() == reflect.Float64)fmt.Println("value:", v.Float())

pritns

type: float64kind is float64: truevalue: 3.4

Type!and!Kindvar 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 intvar x MyInt = 7v := reflect.ValueOf(x)fmt.Println("kind is Int: ", v.Kind() == reflect.Int) // true.

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 float64fmt.Println(y)fmt.Printf("value is %7.1e\n", 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.

3.#To#modify#a#reflec0on#object,#the#value#must#be#se;able

var x float64 = 3.4v := reflect.ValueOf(x)v.SetFloat(7.1) // Error: will panic.// panic: reflect.Value.SetFloat using unaddressable valuevar x float64 = 3.4v := reflect.ValueOf(x)fmt.Println("settability of v:", v.CanSet())// settability of v: false

What%is%"se$ability"?

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?

"Use%the%pointer,%Luke."

var x float64 = 3.4p := reflect.ValueOf(&x) // Note: take the address of x.fmt.Println("type of p:", p.Type())// type of p: *float64fmt.Println("settability of p:", p.CanSet())// settability of p: falsev := p.Elem()fmt.Println("settability of v:", v.CanSet())// settability of v: truev.SetFloat(7.1)fmt.Println(v.Interface())// 7.1fmt.Println(x)// 7.1

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 = %v\n", 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}

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

reflect!Package

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{} != nilfunc DeepEqual(a1, a2 interface{}) boolfunc Select(cases []SelectCase) (chosen int, recv Value, recvOK bool)

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)

Typestype ChanDir // A channel type's direction func (d ChanDir) String() stringtype Kind // The specific kind of type func (k Kind) String() stringtype Method // A single methodtype SelectCase // A single select casetype SelectDir // The communication directiontype SliceHeader // A slicetype StringHeader // A stringtype StructField // A single field in a structtype StructTag // The tag in a struct field func (tag StructTag) Get(key string) stringtype Type // A Go typetype Value // A Go valuetype ValueError // Error for Value func (e *ValueError) Error() string

Type!related!func,ons

func ChanOf(dir ChanDir, t Type) Typefunc MapOf(key, elem Type) Typefunc PtrTo(t Type) Typefunc SliceOf(t Type) Typefunc TypeOf(i interface{}) Type

Type!interfacetype 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 ...

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}

Value!related!func,onsfunc Append(s Value, x ...Value) Valuefunc AppendSlice(s, t Value) Valuefunc Indirect(v Value) Valuefunc MakeChan(typ Type, buffer int) Valuefunc MakeFunc(typ Type, fn func(args []Value) (results []Value)) Valuefunc MakeMap(typ Type) Valuefunc MakeSlice(typ Type, len, cap int) Valuefunc New(typ Type) Valuefunc NewAt(typ Type, p unsafe.Pointer) Valuefunc ValueOf(i interface{}) Valuefunc Zero(typ Type) Value

Value!methods:!Type!and!kindfunc (v Value) Addr() Valuefunc (v Value) Bool() boolfunc (v Value) Bytes() []bytefunc (v Value) Complex() complex128func (v Value) Float() float64func (v Value) Int() int64func (v Value) Interface() (i interface{})func (v Value) InterfaceData() [2]uintptrfunc (v Value) Kind() Kindfunc (v Value) Pointer() uintptrfunc (v Value) Slice(i, j int) Valuefunc (v Value) Slice3(i, j, k int) Valuefunc (v Value) String() stringfunc (v Value) Type() Typefunc (v Value) Uint() uint64func (v Value) UnsafeAddr() uintptr

Value!methods:!Can_,!Is_!and!Overflow_

func (v Value) CanAddr() boolfunc (v Value) CanInterface() boolfunc (v Value) CanSet() bool

func (v Value) IsNil() boolfunc (v Value) IsValid() bool

func (v Value) OverflowComplex(x complex128) boolfunc (v Value) OverflowFloat(x float64) boolfunc (v Value) OverflowInt(x int64) boolfunc (v Value) OverflowUint(x uint64) bool

Value!methods:!Array,!Slice!and!Map

func (v Value) Index(i int) Valuefunc (v Value) Cap() intfunc (v Value) Len() int

func (v Value) MapIndex(key Value) Valuefunc (v Value) MapKeys() []Value

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) boolfunc (v Value) Close()

Value!methods:!Func.on!and!method

func (v Value) Call(in []Value) []Valuefunc (v Value) CallSlice(in []Value) []Valuefunc (v Value) Method(i int) Valuefunc (v Value) MethodByName(name string) Valuefunc (v Value) NumMethod() int

Value!methods:!Field!of!structfunc (v Value) Field(i int) Valuefunc (v Value) FieldByIndex(index []int) Valuefunc (v Value) FieldByName(name string) Valuefunc (v Value) FieldByNameFunc(match func(string) bool) Valuefunc (v Value) NumField() int

Value!methods:!Se+ersfunc (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)

Value!methods:!Value!manipula0on

func (v Value) Convert(t Type) Valuefunc (v Value) Elem() Value

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))}

Example:)StructTagpackage 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"))

}

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))}

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), }}

Example:)codegangsta/injectfunc (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}

Example:)codegangsta/injectfunc (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}

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.

The$end$of$slides.$Any$ques1on?

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

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

top related