Why Reflection
Sometimes we need to write a function capable of dealing uniformly with values of types that don’t satisfy a common interface, don’t have a known representation, or don’t exist at the time we design the function—or even all three.
- type switch 不可能枚举所有的类型,就算可能也不应该这样做,否则会出现使用 type switch 的实现的公共库反倒要依赖调用它的库里定义的类型的情况。
Go provides a mechanism called reflection to update variables and inspect their values at run time, to call their methods, and to apply the operations intrinsic to their representation, all without knowing their types at compile time.
fmt,encoding/json,encoding/xml,text/template,html/template, 这些包的实现都依赖于反射。- Reflection is provided by the
reflectpackage.
Reflection is complex to reason about and not for casual use. Where possible, you should avoid exposing reflection in the API of a package.
reflect.Type
reflect.Type 表示 Go 的一种类型,它是接口类型,包含许多方法来区分类型、检查组成(如结构体字段、函数参数等),对它的唯一实现就是 type descriptor。
reflect.TypeOf 接收一个 interface{} 类型的参数,返回的是参数的动态类型(具体类型的入参被转成的 interface value),即 reflect.Type 类型。
reflect.Typeis capable of representing interface types too.
| |
- An assignment from a concrete value to an interface type performs an implicit interface conversion, which creates an interface value consisting of two components: its dynamic type is the operand’s type (
int) and its dynamic value is the operand’s value (3). reflect.Type满足fmt.Stringer接口,String()返回的是它的 interface value 动态类型;fmt.Printf("%T")是这一过程的简写。
| |
- Because
reflect.TypeOfreturns an interface value’s dynamic type, it always returns a concrete type.
reflect.Value
A reflect.Value can hold a value of any type.
reflect.ValueOf 接收一个 interface{} 类型的参数,返回一个包含参数的动态值的 reflect.Value。
- As with
reflect.TypeOf, the results ofreflect.ValueOfare always concrete, but areflect.Valuecan hold interface values too.
| |
reflect.Value满足fmt.Stringer接口,但只有reflect.Value装的是字符串时会返回具体的值,其它情况都只会返回类型。fmt.Printf("%v")会打印值,它对reflect.Values做了特殊处理。- Calling the
Typemethod on areflect.Valuereturns its type as areflect.Type.
| |
- The inverse operation to
reflect.ValueOfis thereflect.Value.Interfacemethod. It returns aninterface{}holding the same concrete value as thereflect.Value
reflect.Value 和 interface{} 都能容纳任意值,区别是 interface{} 隐藏了值的 representation and intrinsic operations,也不暴露出任何方法,因此只有知道它的动态类型再去断言才能用起来,而 reflect.Value 有很多方法可以用来检查它的内容。
- 见以下
Display示例。 - Unexported fields are visible to reflection.
| |
reflect.Value的Kind()方法可以返回种类。Kindis concerned only with the underlying representation.
- 类型是无穷的(所以断言行不通),但类型的种类是有限的。
- The basic types
Bool,String, and all the numbers; the aggregate typesArrayandStruct; the reference typesChan,Func,Ptr,Slice, andMap;Interfacetypes; and finallyInvalid, meaning no value at all. - The zero value of a
reflect.Valuehas kindInvalid.
- The basic types
Setting Variables with reflect.Value
Some reflect.Valuess are addressable; others are not.
| |
- The value within
ais a copy of the integer 2. The same is true ofb. The value withincis a copy of the pointer value&x. d, derived fromcby dereferencing the pointer within it, refers to a variable and is thus addressable.- No
reflect.Valuereturned byreflect.ValueOf(x)is addressable. We can use this approach, callingreflect.ValueOf(&x).Elem(), to obtain an addressableValuefor any variablex. We obtain an addressablereflect.Valuewhenever we indirect through a pointer, even if we started from a non-addressableValue.- For example, since the slice indexing expression
e[i]implicitly follows a pointer, it is addressable even if the expressioneis not. By analogy,reflect.ValueOf(e).Index(i)refers to a variable, and is thus addressable even ifreflect.ValueOf(e)is not.
- For example, since the slice indexing expression
| |
Application
formatAtom
formatAtom treats each value as an indivisible thing with no internal structure.
| |
- For aggregate types (structs and arrays) and interfaces it prints only the type of the value.
- For reference types (channels, functions, pointers, slices, and maps), it prints the type and the reference address in hexadecimal.
Display
Given an arbitrarily complex value x, Display prints the complete structure of that value, labeling each element with the path by which it was found.
| |
reflect.Slice,reflect.Array:Len(),Index()reflect.Struct:NumField(),Field()reflect.Ptr:IsNil(),Elem()
- Cannot handle cycles in the object graph.