TheRiver | blog

You have reached the world's edge, none but devils play past here

0%

golang reflect

author title version
TheRiver golang reflect go version go1.15.2 darwin/amd64

前言

在计算机学中,反射(英语:reflection)是指计算机程序在运行时(runtime)可以访问、检测和修改它本身状态或行为的一种能力。[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

反射主要的两个类型:TypeValue,结合函数TypeofValueof使用。看下代码是怎么实现的:

Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Type is the representation of a Go type.
// 并非所有方法都适用于所有类型。在每种方法的文档中都注明了限制(如有)
// Not all methods apply to all kinds of types. Restrictions,
// if any, are noted in the documentation for each method.
// 在调用特定于种类的方法之前,请使用Kind方法找出类型。调用不适合该类型的方法会导致运行时panic。
// Use the Kind method to find out the kind of type before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
//
// Type values are comparable, such as with the == operator,
// so they can be used as map keys.
// Two Type values are equal if they represent identical types.
type Type interface {
// Methods applicable to all types.

// Align returns the alignment in bytes of a value of
// this type when allocated in memory.
//内存对齐字节数
Align() int

// FieldAlign returns the alignment in bytes of a value of
// this type when used as a field in a struct.
//结构体中对齐字节数
FieldAlign() int

// Method returns the i'th method in the type's method set.
// It panics if i is not in the range [0, NumMethod()).
//非接口类型,返回带接受者的方法
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//接口类型,返回函数签名,不带接收者
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
//
// Only exported methods are accessible and they are sorted in
// lexicographic order.

//返回第i个method
Method(int) Method

// MethodByName returns the method with that name in the type's
// method set and a boolean indicating if the method was found.
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
//返回对应名字的method
MethodByName(string) (Method, bool)

// NumMethod returns the number of exported methods in the type's method set.
//返回method的总数
NumMethod() int

// Name returns the type's name within its package for a defined type.
// For other (non-defined) types it returns the empty string.
//返回类型名
Name() string

// PkgPath returns a defined type's package path, that is, the import path
// that uniquely identifies the package, such as "encoding/base64".
// If the type was predeclared (string, error) or not defined (*T, struct{},
// []int, or A where A is an alias for a non-defined type), the package path
// will be the empty string.
PkgPath() string

// Size returns the number of bytes needed to store
// a value of the given type; it is analogous to unsafe.Sizeof.
Size() uintptr

// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
// guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
//返回字符串的类型描述,比较类型的话直接用Type别用这个
String() string

// Kind returns the specific kind of this type.
//返回特定的类型
Kind() Kind

// Implements reports whether the type implements the interface type u.
Implements(u Type) bool

// AssignableTo reports whether a value of the type is assignable to type u.
//
AssignableTo(u Type) bool

// ConvertibleTo reports whether a value of the type is convertible to type u.
ConvertibleTo(u Type) bool

// Comparable reports whether values of this type are comparable.
Comparable() bool

// Methods applicable only to some types, depending on Kind.
// The methods allowed for each kind are:
//
// Int*, Uint*, Float*, Complex*: Bits
// Array: Elem, Len
// Chan: ChanDir, Elem
// Func: In, NumIn, Out, NumOut, IsVariadic.
// Map: Key, Elem
// Ptr: Elem
// Slice: Elem
// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField

// Bits returns the size of the type in bits.
// It panics if the type's Kind is not one of the
// sized or unsized Int, Uint, Float, or Complex kinds.
Bits() int

// ChanDir returns a channel type's direction.
// It panics if the type's Kind is not Chan.
ChanDir() ChanDir

// IsVariadic reports whether a function type's final input parameter
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
// For concreteness, if t represents func(x int, y ... float64), then
//
// t.NumIn() == 2
// t.In(0) is the reflect.Type for "int"
// t.In(1) is the reflect.Type for "[]float64"
// t.IsVariadic() == true
//
// IsVariadic panics if the type's Kind is not Func.
IsVariadic() bool

// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
//返回元素类型
Elem() Type

// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
//返回第i个字段
Field(i int) StructField

// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
FieldByIndex(index []int) StructField

// FieldByName returns the struct field with the given name
// and a boolean indicating if the field was found.
//返回对应名称的字段
FieldByName(name string) (StructField, bool)

// FieldByNameFunc returns the struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
//
// FieldByNameFunc considers the fields in the struct itself
// and then the fields in any embedded structs, in breadth first order,
// stopping at the shallowest nesting depth containing one or more
// fields satisfying the match function. If multiple fields at that depth
// satisfy the match function, they cancel each other
// and FieldByNameFunc returns no match.
// This behavior mirrors Go's handling of name lookup in
// structs containing embedded fields.
FieldByNameFunc(match func(string) bool) (StructField, bool)

// In returns the type of a function type's i'th input parameter.
// It panics if the type's Kind is not Func.
// It panics if i is not in the range [0, NumIn()).
//第i个入参
In(i int) Type

// Key returns a map type's key type.
// It panics if the type's Kind is not Map.
Key() Type

// Len returns an array type's length.
// It panics if the type's Kind is not Array.
Len() int

// NumField returns a struct type's field count.
// It panics if the type's Kind is not Struct.

//字段数量
NumField() int

// NumIn returns a function type's input parameter count.
// It panics if the type's Kind is not Func.
//函数入参个数
NumIn() int

// NumOut returns a function type's output parameter count.
// It panics if the type's Kind is not Func.
//函数出参个数
NumOut() int

// Out returns the type of a function type's i'th output parameter.
// It panics if the type's Kind is not Func.
// It panics if i is not in the range [0, NumOut()).
//第i个出参
Out(i int) Type

common() *rtype
uncommon() *uncommonType
}

简单测试下常用的函数:

Name

Name() string, Name returns the type’s name within its package for a defined type.For other (non-defined) types it returns the empty string.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"fmt"
"reflect"
)

var data = struct {
name string
id int
family []string
}{
name: "river",
id: 1,
family: []string{"me", "you", "we"},
}

type data2 struct {
name string
id int
family []string
}

func main() {
t := reflect.TypeOf(data)
fmt.Println(t.Name()) //

t2 := reflect.TypeOf(data2{})
fmt.Println(t2.Name()) //data2
}

String

String() string, String returns a string representation of the type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
"reflect"
)

type data struct {
name string
id int
family []string
}

func main() {
t := reflect.TypeOf(data{})
fmt.Println(t.String()) //main.data
fmt.Println(t.Name()) //data
}

Len

Len() int, Len returns an array type’s length.

It panics if the type’s Kind is not Array.

demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
"reflect"
)

type data struct {
name string
id int
family []string
}

func main() {
t := reflect.TypeOf([10]data{})
fmt.Println(t.Len()) //10
}

Elem

Elem() Type ,Elem returns a type’s element type.

It panics if the type’s Kind is not Array, Chan, Map, Ptr, or Slice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
"reflect"
)

type data struct {
name string
id int
family []string
}

func main() {
//t := reflect.TypeOf(data{name: "river"}) panic
t := reflect.TypeOf(&data{name: "river"})
fmt.Println(t.Elem()) //main.data
}

Kind

Kind() Kind, Kind returns the specific kind of this type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"reflect"
)

type data struct {
name string
id int
family []string
}

func main() {
t := reflect.TypeOf(data{name: "river"})
fmt.Println(t.Kind()) //struct
}

kind返回的值类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/*
* These data structures are known to the compiler (../../cmd/internal/gc/reflect.go).
* A few are known to ../runtime/type.go to convey to debuggers.
* They are also known to ../runtime/type.go.
*/

// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind uint

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
)

Method

Method(int) Method
MethodByName(string) (Method, bool)
NumMethod() int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import (
"fmt"
"reflect"
)

type data struct {
name string
id int
family []string
}

func (d data) Func1() {
fmt.Println("1")
}

func (d data) Func2() {
fmt.Println("2")
}

func (d *data) Func3() {
fmt.Println("3")
}

func (d data) func4() {
fmt.Println("4")
}

func main() {
t := reflect.TypeOf(data{name: "river"})
t2 := reflect.TypeOf(&data{name: "river"})
fmt.Println(t.NumMethod()) //2
fmt.Println(t2.NumMethod()) //3
fmt.Println(t.Method(0).Name) //Func1
fmt.Println(t.MethodByName("Func2")) //{Func2 func(main.data) <func(main.data) Value> 1} true
}

函数名要大写,不然num不增加。绑定到指针类型的方法和绑定到对象的方法对于指针的NUM和对象的NUM的计数是不同的

Field

NumField() int
Field(i int) StructField
FieldByIndex(index []int) StructField
FieldByName(name string) (StructField, bool)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

type Log struct {
Id int
Time string
User int
}

type Manager struct {
User User
Log Log
}

// Main function
func main() {

m := Manager{User: User{1, "Jack", 12}, Log: Log{1, "20:01:01", 10000}}
t := reflect.TypeOf(m)
fmt.Printf("%#v\n", t.Field(0))
fmt.Printf("%#v \n", t.Field(1))
fmt.Println("")

// use of FieldByIndex() method
fmt.Println(t.FieldByIndex([]int{0, 0}).Name)
fmt.Println(t.FieldByIndex([]int{0, 1}).Name)
fmt.Println(t.FieldByIndex([]int{0, 2}).Name)
fmt.Println("")

fmt.Println(t.FieldByIndex([]int{1, 0}).Name)
fmt.Println(t.FieldByIndex([]int{1, 1}).Name)
fmt.Println(t.FieldByIndex([]int{1, 2}).Name)
fmt.Println("")

fmt.Println(t.FieldByName("User"))
fmt.Println(t.FieldByName("Name"))
}

output:

1
2
3
4
5
6
7
8
9
10
11
12
13
reflect.StructField{Name:"User", PkgPath:"", Type:(*reflect.rtype)(0x10bfd20), Tag:"", Offset:0x0, Index:[]int{0}, Anonymous:false}
reflect.StructField{Name:"Log", PkgPath:"", Type:(*reflect.rtype)(0x10bfc60), Tag:"", Offset:0x20, Index:[]int{1}, Anonymous:false}

Id
Name
Age

Id
Time
User

{User main.User 0 [0] false} true
{ <nil> 0 [] false} false

In Out

In(i int) Type
NumIn() int
Out(i int) Type
NumOut() int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
"fmt"
"reflect"
)

func func1(In1 int, In2 string) (Out1 int, Out2 int) {
return 1, 2
}

type HHello struct{}

func (h *HHello) Hello(req string, rep *string) error {
*rep = "hello:" + req
return nil
}

// Main function
func main() {
//函数
t := reflect.TypeOf(func1)
for i := 0; i < t.NumIn(); i++ {
fmt.Println(t.In(i))
}
fmt.Println("-------------")

for i := 0; i < t.NumOut(); i++ {
fmt.Println(t.Out(i))
}
fmt.Println("-------------")

//方法
typ := reflect.TypeOf(new(HHello))
fmt.Println(typ.NumMethod())
m := typ.Method(0)
mt := m.Type
fmt.Println(mt.NumIn())
for i := 0; i < mt.NumIn(); i++ {
fmt.Println(mt.In(i))
}
}

output:

1
2
3
4
5
6
7
8
9
10
11
int
string
-------------
int
int
-------------
1
3
*main.HHello
string
*string

方法的入参个数是算接受者的.


Value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// Value is the reflection interface to a Go value.
//
// Not all methods apply to all kinds of values. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of value before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run time panic.
//
// The zero Value represents no value.
// Its IsValid method returns false, its Kind method returns Invalid,
// its String method returns "<invalid Value>", and all other methods panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
//
// A Value can be used concurrently by multiple goroutines provided that
// the underlying Go value can be used concurrently for the equivalent
// direct operations.
//
// To compare two Values, compare the results of the Interface method.
// Using == on two Values does not compare the underlying values
// they represent.
type Value struct {
// typ holds the type of the value represented by a Value.
//指向类型的指针
typ *rtype

// Pointer-valued data or, if flagIndir is set, pointer to data.
// Valid when either flagIndir is set or typ.pointers() is true.
//指向值得指针
ptr unsafe.Pointer

// flag holds metadata about the value.
// The lowest bits are flag bits:
// - flagStickyRO: obtained via unexported not embedded field, so read-only
// - flagEmbedRO: obtained via unexported embedded field, so read-only
// - flagIndir: val holds a pointer to the data
// - flagAddr: v.CanAddr is true (implies flagIndir)
// - flagMethod: v is a method value.
// The next five bits give the Kind of the value.
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
// If ifaceIndir(typ), code can assume that flagIndir is set.
flag

// A method value represents a curried method invocation
// like r.Read for some receiver r. The typ+val+flag bits describe
// the receiver r, but the flag's Kind bits say Func (methods are
// functions), and the top bits of the flag give the method number
// in r's type's method table.
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//func (v Value) pointer() unsafe.Pointer {}
func (v Value) Addr() Value {}
//func (v Value) Bool() bool {}
//func (v Value) Bytes() []byte {}
//func (v Value) runes() []rune {}
func (v Value) CanAddr() bool {}
func (v Value) CanSet() bool {}
func (v Value) Set(x Value) {}

func (v Value) Call(in []Value) []Value {}
//func (v Value) CallSlice(in []Value) []Value {}
//func (v Value) call(op string, in []Value) []Value {}
//func (v Value) Cap() int {}
func (v Value) Elem() Value {}

func (v Value) Field(i int) Value {}
func (v Value) NumField() int {}
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) Index(i int) Value {}
//func (v Value) Int() int64 {}
func (v Value) Interface() (i interface{}) {}
//func (v Value) IsValid() bool {}
//func (v Value) IsZero() bool {}
func (v Value) Kind() Kind {}
//func (v Value) Len() int {}

func (v Value) Method(i int) Value {
func (v Value) NumMethod() int {
func (v Value) MethodByName(name string) Value {}

func (v Value) String() string {}
func (v Value) Type() Type {}
...

String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

// Main function
func main() {
v := reflect.ValueOf(User{Id: 1, Name: "river", Age: 26})
fmt.Println(v.String()) //<main.User Value>

t := reflect.TypeOf(User{Id: 1, Name: "river", Age: 26})
fmt.Println(t.String()) //main.User
}

Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

// Main function
func main() {
v := reflect.ValueOf(User{Id: 1, Name: "river", Age: 26})
fmt.Println(v.Type()) //main.User
}

Index

Index returns v’s i’th element.

It panics if v’s Kind is not Array, Slice, or String or i is out of range.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
"reflect"
)

// Main function
func main() {
a := [2]int{1, 2}
s := []int{3, 4}
str := "abcd"

v := reflect.ValueOf(a)
fmt.Println(v.Index(1)) //2

v = reflect.ValueOf(s)
fmt.Println(v.Index(1)) //4

v = reflect.ValueOf(str)
fmt.Println(v.Index(1)) //98
}

Elem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Elem returns the value that the interface v contains
// or that the pointer v points to.
// It panics if v's Kind is not Interface or Ptr.
// It returns the zero Value if v is nil.

package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

// Main function
func main() {
//v := reflect.ValueOf(User{Id: 1, Name: "river", Age: 26})
//fmt.Println(v.Elem()) //panic

v := reflect.ValueOf(&User{Id: 1, Name: "river", Age: 26})
fmt.Println(v.Elem()) //{1 river 26}

// var vv reflect.Value
// fmt.Println(vv.Elem()) //panic

v = reflect.ValueOf(&User{})
fmt.Println(v.Elem()) //{0 0}
}

Call

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

func (u User) Printt() {
fmt.Println("yes")
}

// Main function
func main() {
v := reflect.ValueOf(User{Id: 1, Name: "river", Age: 26})
var r []reflect.Value
v.Method(0).Call(r) //yes
}

Kind

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
}

func ff() {

}

// Main function
func main() {
v := reflect.ValueOf(User{Id: 1, Name: "river", Age: 26})
fmt.Println(v.Kind()) //struct

v = reflect.ValueOf(1)
fmt.Println(v.Kind()) //int

v = reflect.ValueOf("2222")
fmt.Println(v.Kind()) //string

v = reflect.ValueOf([]int{1, 2, 3})
fmt.Println(v.Kind()) //slice

v = reflect.ValueOf(ff)
fmt.Println(v.Kind()) //func
}

感觉和Type的Kind没啥区别

Set Addr

CanAddr reports whether the value’s address can be obtained with Addr. Such values are called addressable. A value is addressable if it is an element of a slice, an element of an addressable array, a field of an addressable struct, or the result of dereferencing a pointer. If CanAddr returns false, calling Addr will panic.

反射中这几种值可以寻址:

  • 切片的一个元素(ValueOf().Index())
  • 可寻址数组的一个元素
  • 可寻址结构体的一个字段
  • 解引用的结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package main

import (
"fmt"
"reflect"
)

type User struct {
Id int
Name string
Age int
pi *int
}

// Main function
func main() {
v := reflect.ValueOf(User{Id: 1, Name: "river", Age: 26})
fmt.Println("1: ", v.CanAddr(), v.CanSet()) //false false

v = reflect.ValueOf(&User{Id: 1, Name: "river", Age: 26})
fmt.Println("2: ", v.CanAddr(), v.CanSet()) //false false

p := 10
u := User{Id: 1, Name: "river", Age: 26, pi: &p}
v = reflect.ValueOf(&u.pi)
fmt.Println("3: ", v.CanAddr(), v.CanSet()) //false false

s := []int{1, 2, 3}
v = reflect.ValueOf(s)
fmt.Println("4: ", v.CanAddr(), v.CanSet()) //false false

s = []int{1, 2, 3}
v = reflect.ValueOf(s[0])
fmt.Println("5: ", v.CanAddr(), v.CanSet()) //false false

s = []int{1, 2, 3}
v = reflect.ValueOf(&s[1])
fmt.Println("6: ", v.CanAddr(), v.CanSet()) //false false

s = []int{1, 2, 3}
v = reflect.ValueOf(s).Index(0)
fmt.Println("7: ", v.CanAddr(), v.CanSet()) //true true

v = reflect.ValueOf(&p)
fmt.Println("8: ", v.CanAddr(), v.CanSet()) //false false

v = reflect.ValueOf(&p).Elem()
fmt.Println("9: ", v.CanAddr(), v.CanSet()) //true true

v = reflect.Indirect(reflect.ValueOf(&p))
fmt.Println("10: ", v.CanAddr(), v.CanSet()) //true true

ss := [3]int{1, 2, 3}
v = reflect.ValueOf(ss).Index(0)
fmt.Println("11: ", v.CanAddr(), v.CanSet()) //false false

v = reflect.ValueOf(User{Id: 1, Name: "river", Age: 26}).Field(0)
fmt.Println("12: ", v.CanAddr(), v.CanSet()) //false false

}

这个寻址可以说非常严格了,4条规则我也是没搞懂太含糊了。只能说解引用是最保险的了。

Interface

类型转换成interface(),还原到ValueOf的入参。结合addr可以修改值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"fmt"
"reflect"
)

// Main function
//1
func main() {
i := 10
add := reflect.ValueOf(&i).Elem()
pi := add.Addr().Interface().(*int)
*pi = 20
fmt.Println(i)
}

//2
func main() {
i := 10
add := reflect.ValueOf(&i).Elem()
if add.CanSet() {
add.Set(reflect.ValueOf(20))
}
fmt.Println(i)
}

Method

参考Type的函数

Field

参考Type的函数


Elem and Indirect

golang - Elem Vs Indirect in the reflect package

If a reflect.Value is a pointer, then v.Elem() is equivalent to reflect.Indirect(v). If it is not a pointer, then they are not equivalent:

  • If the value is an interface then reflect.Indirect(v) will return the same value, while v.Elem() will return the contained dynamic value.
  • If the value is something else, then v.Elem() will panic.

The reflect.Indirect helper is intended for cases where you want to accept either a particular type, or a pointer to that type. One example is the database/sql conversion routines: by using reflect.Indirect, it can use the same code paths to handle the various types and pointers to those types.

总结

  • Type是接口,Value是结构体和方法
  • 函数名要大写,不然num不增加。绑定到指针类型的方法和绑定到对象的方法对于指针的NUM和对象的NUM的计数是不同的
  • 可寻址的条件是很苛刻的
  • canset比canaddr多了一个限制,即内部是exported的
  • 结合addr和interface可以修改值,或者set
  • Elem和Indirect在都是指针的时候没有区别
  • 东西挺多的,以后遇到了再补充

参考

golang - Elem Vs Indirect in the reflect package

go addressable 详解

https://www.geeksforgeeks.org/

深入理解Golang之interface和reflect

----------- ending -----------