跳到主要内容

reflection

The Laws of Reflection

https://go.dev/blog/laws-of-reflection

The representation of an interface

A variable of interface type stores a pair: the concrete value assigned to the variable, and that value’s type descriptor

var r io.Reader
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
if err != nil {
return nil, err
}
r = tty

r contains, schematically, the (value, type) pair, (tty, *os.File)

One important detail is that the pair inside an interface variable always has the form (value, concrete type) and cannot have the form (value, interface type). Interfaces do not hold interface values

Reflection goes from interface value to reflection object

reflection is just a mechanism to examine the type and value pair stored inside an interface variable

two simple functions, called reflect.TypeOf and reflect.ValueOf, retrieve reflect.Type and reflect.Value pieces out of an interface value

// TypeOf returns the reflection Type of the value in the interface{}.
func TypeOf(i interface{}) Type

both Type and Value have a Kind method that returns a constant indicating what sort of item is stored: Uint, Float64, Slice, and so on

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

The second property is that the Kind of a reflection object describes the underlying type, not the static type

Reflection goes from reflection object to interface value

Given a reflect.Value we can recover an interface value using the Interface method; in effect the method packs the type and value information back into an interface representation and returns the result

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

To modify a reflection object, the value must be settable

Settability is determined by whether the reflection object holds the original item

var x float64 = 3.4
p := reflect.ValueOf(&x) // Note: take the address of x.
fmt.Println("type of p:", p.Type())
fmt.Println("settability of p:", p.CanSet())

v := p.Elem()
fmt.Println("settability of v:", v.CanSet())

Structs

type T struct {
A int
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())
}

stdlib reflect

https://pkg.go.dev/reflect