NOTE
1.2 reflection
What reflection is, how Go implements reflection through interfaces, and the relationship between Type and Value.
This is a historical learning note and may contain outdated or incomplete understanding.
1. What Is Reflection
Modify code -> compile -> run. Normally, code can only be changed before compilation. Reflection allows us to modify things at runtime.
2. How Go Implements Reflection
Interface. When a concrete type is assigned to an interface variable, the interface stores the type information of that concrete value. Reflection is implemented through the type information stored in the interface. interface.md
3. Type and Value
3.1. The reflect package defines a (Type, Value) pair

3.2. Obtain Type through reflect.TypeOf
It is closely related to _type (the dynamic type).
type emptyInterface struct {
typ *rtype// dynamic type
word unsafe.Pointer
}
func TypeOf(i interface{}) Type {
// emptyInterface can be regarded as eface. eface is in the runtime package, while emptyInterface is in the reflect package
eface := *(*emptyInterface)(unsafe.Pointer(&i))
// pass in the dynamic type
return toType(eface.typ)
}
// It does nothing special; it simply returns the dynamic type
func toType(t *rtype) Type {
if t == nil {
return nil
}
return t
type Type interface {
// All types can call the following functions
// Number of bytes occupied by a variable of this type after alignment
Align() int
// If it is a struct field, number of bytes occupied after alignment
FieldAlign() int
// Return the i-th method in this type's method set
Method(int) Method
// Get a method by name
MethodByName(string) (Method, bool)
// Get the number of exported methods in this type's method set
NumMethod() int
// Type name
Name() string
// Return the path where the type is located, such as encoding/base64
PkgPath() string
// Return the size of the type, similar to unsafe.Sizeof
Size() uintptr
// Return the string representation of the type
String() string
// Return the kind value of the type
Kind() Kind
// Whether the type implements interface u
Implements(u Type) bool
// Whether it can be assigned to u
AssignableTo(u Type) bool
// Whether it can be converted to u
ConvertibleTo(u Type) bool
// Whether values of the type are comparable
Comparable() bool
// The following functions can only be called by specific types
// For example, Key and Elem can only be called by Map types
// Number of bits occupied by the type
Bits() int
// Return the direction of a channel; only chan types can call this
ChanDir() ChanDir
// Return whether the type is variadic; only func types can call this
// For example, if t has type func(x int, y ... float64)
// then t.IsVariadic() == true
IsVariadic() bool
// Return the internal element type; only Array, Chan, Map, Ptr, or Slice can call this
Elem() Type
// Return the i-th field of a struct type; only struct types can call this
// It panics if i exceeds the total number of fields
Field(i int) StructField
// Return a field in a nested struct
FieldByIndex(index []int) StructField
// Get a field by name
FieldByName(name string) (StructField, bool)
// FieldByNameFunc returns the struct field with a name
// Return the field whose name matches the func function
FieldByNameFunc(match func(string) bool) (StructField, bool)
// Get the type of the i-th parameter of a function type
In(i int) Type
// Return the key type of a map; only map types can call this
Key() Type
// Return the length of an Array; only Array types can call this
Len() int
// Return the number of fields; only Struct types can call this
NumField() int
// Return the number of input parameters of a function type
NumIn() int
// Return the number of return values of a function type
NumOut() int
// Return the type of the i-th return value of a function type
Out(i int) Type
// Return the common part of the type structure
common() *rtype
// Return the uncommon part of the type structure
uncommon() *uncommonType
}}
3.3. Obtain Value through reflect.ValueOf
This combines both _type (the dynamic type) and data (the dynamic value).
func ValueOf(i interface{}) Value {
if i == nil {
return Value{}
}
// ……
return unpackEface(i)
}
// Decompose eface
func unpackEface(i interface{}) Value {
// Convert i to *emptyInterface
e := (*emptyInterface)(unsafe.Pointer(&i))
t := e.typ
if t == nil {
return Value{}
}
// Assemble its typ field, word field, and a flag field into a Value structure
f := flag(t.Kind())
if ifaceIndir(t) {
f |= flagIndir
}
return Value{t, e.word, f}
}
// Value structure
// Set the len field of a slice; panic if the type is not a slice
func (v Value) SetLen(n int)
// Set the cap field of a slice
func (v Value) SetCap(n int)
// Set a map key/value pair
func (v Value) SetMapIndex(key, val Value)
// Return the value at index i of a slice, string, or array
func (v Value) Index(i int) Value
// Get the value of a struct field by name
func (v Value) FieldByName(name string) Value
// Get an int value
func (v Value) Int() int64
// Get the number of struct fields (members)
func (v Value) NumField() int
// Try to send data to a channel (does not block)
func (v Value) TrySend(x reflect.Value) bool
// Call the function (or method) represented by v with argument list in
func (v Value) Call(in []Value) (r []Value)
// Call a variadic function
func (v Value) CallSlice(in []Value) []Value
3.4. Value.Kind returns the built-in kind
type Student struct {
}
// TypeOf returns Student
// Kind returns struct
3.5. Obtain interface{} through Value.Interface()
func testStrType(v interface{}) {
if str, ok := v.(string); ok {
fmt.Println(str)
}
}
func testType(t interface{}) {
switch t.(type) {
case int:
fmt.Println("int type")
case *factory.Stu:
fmt.Println("Stu type")
stu := t.(*factory.Stu)
//stu := *factory.Stu(t)
stu.TestPrintName()
case factory.Learner:
fmt.Println("Learner type")
learner := t.(factory.Learner)
learner.Learn()
}
}
3.6. Modify attribute values through Value.Elem
Reflection can be used to modify the value of a variable, provided that the value can be modified.
4. API
go - Why is IsValid() returning true for the zero value of an int? - Stack Overflow
5. References
- reflection - How do you create a new instance of a struct from its type at run time in Go? - Stack Overflow
- go - cannot convert data (type interface {}) to type string: need type assertion - Stack Overflow
- The Laws of Reflection - The Go Blog
- A Quick-to-Understand Series: Golang Reflection - CSDN Blog
- Deep Dive into Go Reflection | qcrao
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub