-
Notifications
You must be signed in to change notification settings - Fork 0
/
第 11.10.01 章、reflect 包
1037 lines (724 loc) · 33.7 KB
/
第 11.10.01 章、reflect 包
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
reflect 包实现了运行时反射,允许一个程序操控各种类型的对象
常见用法即为:从静态类型 interface{} 中取出一个值,并通过调用 TypeOf,返回一个 Type 类型的值,来获得它的动态类型信息
调用 ValueOf 返回一个 Value 类型的数据,表示运行时数据
Zero 函数获取一个 Type 类型的值,并返回一个代表该类型零值的 Value 类型的值
参见 “The Laws if Reflection” 了解 Go 语言中 reflection 的简介
https://golang.org/doc/articles/laws_of_reflection.html
Copy(dst, src Value) int
将 src 的内容开呗值 dst 中,直到 dst 被填满或者 src 被耗尽
返回拷贝元素的数量
dst 和 src 必须具有 Slice 或 Array 的 kind
且 dst 和 src 必须具有相同的元素类型
DeepEqual(x,y interface{}) bool
返回 x 和 y 是否 “深层相等”
若两个相同类型的值满足以下条件之一,则称之为 “深层相等” 的
<1> Array 值:当它们所含有的元素一一对应 “深层相等” 时
<2> Struct 值:当它们所含字段一一对应 “深层相等” 时(包含导出字段和非导出字段)
<3> Func 值:当它们均为 nil 时,它们 “深层相等”,否则它们 不为 “深层相等”
<4> Interface 值:当它们具有的值 “深层相等” 时,它们 “深层相等”
<5> Map 值:当符合以下全部规则时,它们 “深层相等”
1. 它们要么全部是 nil,要么全部是 非 nil
2. 它们具有相同的长度
3. 它们要么是完全相同的 map 对象,要么对应键名对应的值是 “深层相等” 的
<6> Pointer 值:要么用 Go 操作符 == 返回值为真,要么指向 “深层相等” 的值
<7> Slice 值:当符合以下全部规则时,它们 “深层相等”
1. 它们要么全部是 nil,要么全部是 非 nil
2. 它们具有相同的长度
3. 它们要么指向完全相同的底层 array 的相同条目,要么一一对应的所有元素都是 “深层相等” 的
注意: 非 nil 空 slice 和 nil slice 是 非 “深层相等” 的
eg. []byte{} []byte{nil} 是不同的
<8> 其他值 —— 数字、布尔值、字符串、通道 —— 若它们被 Go 操作符 == 返回真,则为 “深层相等”
大体来说, DeepEqual 就是递归进行 Go 操作符 == 操作
但这个想法和实际必有一些出入
特别的,
有一些值可能和自身不相等,比如 func 值(不可比较的类型)或者 浮点数的 NaN 值(在浮点比较中不相等)
或者 含有上述两种值的 array struct 与 interface
另一方面, pointer 永远与自身相等,即便它们指向了上述两种值,
因为无论它们的内容如何,pointer 总会在 Go 操作符 == 下与自身相等
DeepEqual 函数被设计成为只要 slice 和 map 是完全相同的 slice 和 map,无论内容也会 “深度相等” 的状态
Select(cases []SelectCase) (chosen int, recv Value, recvOK bool)
选择执行被 cases 所描述的一系列操作中的一个
如同 Go 的 select 声明,它会阻塞,直到至少一个 case 可以被执行,做一个均一化随机选择,并执行那个 case
它返回被选中 case 的索引号,若 case 是一个拉取操作,拉取的值被返回,
并且返回一个布尔值,指示出该值是否真的是 send 出来的数据(反例:由于通道关闭,所以接受到一个零值)
Swapper(slice interface{}) func(i, j int)
返回一个翻转输入 slice 的函数
若输入并非 slice 类型,Swapper panic
ChanDir int 类型
表示 channel 类型的方向
const(
RecvDir ChanDir = 1 << iota // <-chan
SendDir // chan<-
BothDir = RecvDir | SendDir // chan
)
(d ChanDir) String() string
满足了 fmt.Stringer 接口
Kind uint 类型
表示了 Type 类型所表示的特定类型
Kind 的零值不是一个有效的 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
)
(k Kind) String() string
满足了 fmt.Stringer 接口
Method struct 类型
代表了一个单独的方法
type Method struct {
// Name 即为方法的名称
// PkgPath 即为小写方法名(非导出方法)的包路径
// 对于大写方法名(导出方法),PkgPath 为空
// Name 和 PkgPath 从一个方法集中确定了一个唯一的方法
// 参见 https://golang.org/ref/spec#Uniqueness_of_identifiers
Name string
PkgPath string
Type Type // 方法的类型
Func Value // 以接受者为第一个参数的函数
Index int // Type.Method 的索引
}
SelectCase struct 类型
一个 SelectCase 描述了正在一个选择操作中的一个单一的 case
case 的 kind 由 Dir,也就是 通信的方向 决定
若 Dir 为 SelectDefault,case 表示了一个默认 case
Chan 和 Send 必须为 zero Value
若 Dir 为 SelectSend,case 表示了一个发送 case
普通情况下, Chan 的底层值必须是 channel,Send 的底层值必须是 channel 可以接受的元素类型
特殊情况,若 Chan 是 ezro Value,那么 case 被忽略, Send 也同样被忽略,此时可以为 zero 或 non-zero
若 Dir 为 SelectRecv,case 表示了一个接受 case
通常情况下,Chan 的底层值必须是是 channel,Send 的底层值必须是 channel 可以接受的元素类型
若 Chan 是 zero Value,那么 case 将被忽略,但 Send 依旧必须为 zero Value
当接收操作被选中, Value 的值就被 Select 函数返回
type SelectCase struct {
Dir SelectDir // case 的方向
Chan Value // 使用的 channel(发送或接接收)
Send Value // 将要发送的值(发送时使用)
}
SelectDir int 类型
描述了一个 select 的 case 的通信方向
const (
SelectSend SelectDir // case Chan<- Send
SelectRecv // case <-Chan
SelectDefault // default
)
SliceHeader struct 类型
运行时 slice 的表现
该类型会随着语言的更新而变动
Data 字段也无法有效保证被它引用的数据不被垃圾回收清理,
所以程序必须持有一个独立且正确的具有类型的指针来指向底层数据
type SliceHeader strcut{
Data uintptr
Len int
Cap int
}
StringHeader struct 类型
运行时 string 的表现
该类型会随着语言的更新而变动
Data 字段也无法有效保证被它引用的数据不被垃圾回收清理,
所以程序必须持有一个独立且正确的具有类型的指针来指向底层数据
type StringHeader struct {
Data uintptr
Len int
}
StructField struct 类型
描述了一个结构体中的单一的一个字段
type StructField struct {
// Name 为字段名
Name string
// PkgPath 使用包路径定位了一个小写(非导出)字段名
// 对于大写(导出)字段名,该位置为空
// 参见 https://golang.org/ref/spec#Uniqueness_of_identifiers
PkgPath string
Type Type // 字段类型
Tag StructTag // 字段标签字符串
Offset uintptr // byte 为标记的字段相对所在结构体的偏移值
Index []int // Type.FieldByIndex 的索引
Anonymous bool // 内嵌字段
}
StructTag string 类型
结构体类型的 标签字符串
为了方便,标签字符串 由 空格分开的 键:"值" 对组成
每个 tag 键都由不含控制符、空格、双引号、冒号的非空字符串构成
每个 tag 值 都由双引号引起,并遵循 Go 字符串的语法
(tag StructTag) Get(key string) string
该方法返回与 tag 键 对应的 tag 值
若没有对应的 tag 键,则返回空字符串
若 tag 不具有常规的格式,则本方法的返回值不可预知
若要明确一个 tag 是否明确被设置为空字符串,使用 Lookup 方法
(tag StructTag) Lookup( key string) (value string, ok bool)
该方法返回 tag 键 对应的 tag 值
若 tag 中存在对应的 tag 键,则返回其值(即便可能是空值)
ok 返回一个 tag 值 是否明确的被设定了
若 tag 不具有常规的格式,则本方法的返回值不可预知
Type interface 类型
该类型表示 Go 的一种类型
并非所有的方法都适用于所有的类型
若有限制,则标注在每个方法的文档中
在调用 每 kind 特定的 方法中,用 Kind 方法找出类型的 kind
对某一 kind 的 类型 调用了不合适的方法,将导致 运行时错误
Type 类型的值是可以比较的,比如使用 == 操作符
若两个 Type 值表示相同的 类型,则它们两者相等
type Type interface {
// 返回以 字节 为单位计算的这种类型的值,在内存中的对齐值
Align() int
// 返回,当该类型的值作为 结构体中的一个字段时,
// 以 字节 为单位计算的这种类型的值,在内存中的对齐值
FieldAlign() int
// 返回该类型的方法集的第 i 个方法
// 若 i 不在范围 [ 0, NumMethod() ) 中时,引发 panic
//
// 对于 非接口类型 T 或 *T,返回的 Method 类型的值的 Type 字段 和 Func 字段
// 描述了一个首个参数为接受者的函数
//
// 对于一个 接口类型,返回的 Method 类型的值的 Type 字段 给出了方法的签名
// 该方法并不含有接受者,且 Func 字段为 nil
Method(int) Method
// 返回 指定类型的 方法集 中,具有该 方法名 的方法
// 并用一个 布尔值 表示该方法是否被找到
//
// 对于 非接口类型 T 或 *T,返回的 Method 类型的值的 Type 字段 和 Func 字段
// 描述了一个首个参数为接受者的函数
//
// 对于一个 接口类型,返回的 Method 类型的值的 Type 字段 给出了方法的签名
// 该方法并不含有接受者,且 Func 字段为 nil
MethodByName(string) (Method, bool)
// 返回指定类型的 方法集中 导出的方法的数量
NumMethod() int
// 返回指定类型 在它所在包内的 类型名
// 对于未命名类型,会返回空字符串
Name() string
// 返回一个命名过的类型的 包路径
// 也就是确定该包唯一位置的 导入路径,比如 "encoding/base64"
// 若类型是 预声明的(比如 string 和 error) 或者 未命名的(比如 *T struct{} 和 []int)
// 则 包路径 为空字符串
PkgPath() string
// 返回要存储一个指定类型的值,需要多少字节的存储空间
// 与 unsafe.Sizeof 函数相似
Size() uintptr
// 返回用字符串表示的类型
// 字符串可能会使用短包名称(比如说:使用 base64 而非 encoding/base64)
// 因此不能保证在不同类型之间的唯一性
// 测试类型的身份,请直接比较 Type 值
String() string
// 返回这个类型的 kind
Kind() Kind
// 报告这个类型是否实现了接口类型 u
Implements(u Type) bool
// 报告该类型的值是否可以被赋予至 类型 u 中
AssignableTo(u Type) bool
// 报告该类型的值是否可以被转换为 类型 u
ConvertibleTo(u Type) bool
// 报告该类型的值之间是否可以做比较
Comparable() bool
// 返回以 位 为单位计算的类型的大小
// 若类型的 Kind 并非 sized 或 unsized 的 Int Uint Float Complex 类中的任何一个
// 则引发 panic
Bits() int
// ChanDir returns a channel type's direction.
// It panics if the type's Kind is not Chan.
// 返回一个 通道 类型的方向
// 若 类型的 Kind 值不是 Chan,则引发 panic
ChanDir() ChanDir
// 报告一个函数类型的输入形参的最后一个参数是否为 "..."
// 若是如此,则 t.In(t.NumIn() - 1) 返回参数隐含的实际类型 []T
//
// 具体来说,若 t 代表了 func(x int, y ... float64), 那么
//
// t.NumIn() == 2
// t.In(0) 是 “int” 的 reflect.Type
// t.In(1) 是 “[]float64” 的 reflect.Type
//
// 若方法接受者的类型的 Kind 并非 Func,则引发 panic
IsVariadic() bool
// 返回一个类型的元素的类型
// 若方法接受者的 Kind 并非 Array/Chan/Map/Ptr 或者 Slice,则引发 panic
Elem() Type
// 返回一个结构体类型的第 i 个字段
// 若接受者的 Kind 并非 Struct,则引发 panic
// 若 i 不在 [0, NumField()) 范围内,则引发 panic
Field(i int) StructField
// 返回在索引排序下的结构体嵌套字段
// 等价于 对于每个索引 i 都调用 Field 方法
// 若接受者的 Kind 并非 Struct。则引发 panic
FieldByIndex(index []int) StructField
// 用给定的名称找到结构体的字段,并用一个布尔值指示是否找到该字段
FieldByName(name string) (StructField, bool)
// 返回一个满足名称匹配函数的结构体字段名,并用一个布尔值指示是否寻找到该字段
//
// 本方法首先分析结构体本身的字段,然后是任何匿名结构体的字段
// 依照广度优先的顺序,在匹配上的最浅层停止
// 若在同一级有多个字段被匹配上,则它们相互抵消,本方法返回无匹配
// 这个行为是 Go 处理含有匿名字段结构体的名称查找时的行为
FieldByNameFunc(match func(string) bool) (StructField, bool)
// 返回一个函数的类型的第 i 个输入形参的类型
// 若接受者的 Kind 并非 Func,则引发 panic
// 若 i 不在区间 [0, NumIn()),则引发 panic
In(i int) Type
// 返回一个 map 类型的 键的类型
// 若 接受者的 Kind 并非 Map,则引发 panic
Key() Type
// 返回 array 类型的长度
// 若接受者的 Kind 并非 Array,则引发 panic
Len() int
// 返回结构体的字段的数量
// 若接受者的 Kind 并非 Struct,则引发 panic
NumField() int
// 返回一个函数类型的输入形参的数量
// 若接受者的 Kind 并非 Func,则引发 panic
NumIn() int
// 返回一个函数类型的输出形参的数量
// 若接受者的 Kind 并非 Func,则引发 panic
NumOut() int
// 返回一个函数类型的第 i 个输出形参的类型
// 若接受者的 Kind 并非 Func,则引发 panic
// 若 i 不在区间 [0, NumOut()) 中,则引发 panic
Out(i int) Type
// 包含其他过滤掉的或者未导出的字段
}
ArrayOf(count int, elem Type) Type
返回以指定的元素数量和元素类型所组成的 Array 类型的 Type
eg.
reflect.ArrayOf(5, reflect.TypeOf(1)) 将返回
表示 [5]int 的 reflect.Type 对象
若返回的类型大于可用的内存地址,则 ArrayOf 引发 panic
ChanOf(dir ChanDir, t Type) Type
返回以指定的 channel 方向以及承载数据类型所组成的 channel 类型的 Type
eg.
reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(1)) 将返回
表示 <-chan int 的 reflect.Type 对象
gc 限制了 channel 的元素类型的大小必须小于 64kB
若接受者的其等于或超过这个值,则 ChanOf 引发 panic
FuncOf(in, out []Type, variadic bool) Type
返回以指定的 传入/传出 数据类型以及传入数据的最后一个数据是否变长 所确定的 函数的 Type
eg.
in := []Type{relfect.TypeOf(1)}
out := []Type{reflect.TypeOf("1")}
reflect.FuncOf(in, out, false)
将返回一个签名为 func(int) string 的函数的 reflect.Type 对象
若 in[len(in)-1] 对应的元素并非 slice 对应的 reflect.Type,且 variadic 设置为 true
则 FuncOf 引发 panic
MapOf(key, elem Type) Type
返回指定 键元素类型/值元素类型所组成的 Map 的类型的 reflect.Type 对象
eg.
reflect.MapOf(reflect.TypeOf("1"),reflect.TypeOf(1)) 将返回
表示 map[string]int 的 reflect.Type 对象
若键的类型并非有效类型(也就是没有满足 Go 操作符 == )
则 MapOf 引发 panic
PtrTo(t Type) Type
【注意这个函数是 PtrTo 不是 PtrOf】
返回 指向 指定元素类型 的指针类型的 reflect.Type 对象
eg.
reflect.PtrTo(reflect.TypeOf("a")) 将返回
表示 *string 的 reflect.Type 对象
SliceOf(t Type) Type
返回 指定元素类型所组成的 slice 的类型的 reflect.Type 对象
eg. reflect.SliceOf(reflect.TypeOf(1)) 将返回
表示 []int 的 reflect.Type 对象
StructOf(fields []StructField) Type
返回 由指定的字段类型 组成的结构体的类型 的 reflect.Type 对象
StructFlied 中的 Offset 和 Index 字段将被忽略,并交由编译器决定它们的值
eg.
f1 := reflect.StructField{
Name: "A1",
PkgPath: "",
Type: reflect.TypeOf(1),
Tag: reflect.StructTag("Good"),
Offset: 0,
Index: []int{0},
Anonymous: false,
}
f2 := reflect.StructField{
Name: "A2",
PkgPath: "",
Type: reflect.TypeOf("1"),
Tag: reflect.StructTag("nice"),
Offset: 0,
Index: []int{0},
Anonymous: false,
}
a := reflect.StructOf([]reflect.StructField{f1, f2})
将返回表示 struct { A1 int "Good"; A2 string "nice" } 的 reflect.Type 对象
当前的 StructOf 函数并不会为 内嵌字段 生成 wrapper method
这个限制可能将在未来的版本中移除
TypeOf(i interface{}) Type
返回一个 Type 对象,表示了 i 的动态类型
若 i 是 nil 接口值,则 TypeOf 函数引发 panic
Value struct 类型
本类型是 Go 值的反射接口
并非所有的方法都能作用于所有的值之上
若有任何的限制,请参阅每个方法的文档
在使用 kind-specific 方法前,请使用 Kind 方法确定值的 kind
对值调用错误的方法会导致 运行时 panic
Value 的 零值 表示没有值
它的 IsValid 方法返回 false
它的 Kind 方法返回 Invalid
它的 String 方法返回 "<invalid Value>"
它的其它所有方法都引发 panic
大多数函数和方法绝不会返回一个 invalid Value
若产生了 invalid Value,产生的条件会在方法的文档中注明
若一个 Value 能被多个并发进程使用,则表示其底层的 Go 值可以以同样的方式被多个并发的进程使用
使用 == 来比较两个 Value,并不会比较它们代表的底层值,而是比较 Value 结构体
通过 Interface 方法产生的值来比较两个 Value 对象
Append(s Value, x ...Value) Value
将多个 Value 所表示的值添加至 s 所表示的 slice 中,并返回追加后的切片的 Value
每个 x 所表示的值必须是可以赋予 s 所表示的切片中的
AppendSlice(s, t Value) Value
将 t 表示的 slice 追加至 s 表示的 slice 的后面,并返回追加后的切片的 Value
两个 slice 的内部元素类型必须相同
Indirect(v Value) Value
返回 v 所表示的值 指向的 值的 Value
若 v 所表示的值为 nil pointer,则 Indirect 函数返回 Value 的零值
若 v 所表示的值并非 pointer,则返回 v 本身
MakeChan(typ Type, buffer int) Value
创建一个由指定 数据类型 和 缓冲大小 的表示 channel 的 Value 值
MakeFunc(typ Type, fn func(args []Value) (results []value)) Value
使用 指定的函数类型 “包裹”函数 fn ,并返回这个包裹后的函数
当被包裹后的函数被调用时,执行以下的操作:
<1> 将它的实际参数转化为一个由 Value 值组成的 slice
<2> 运行 results := fn(args)
<3> 将返回值作为一个 slice 返回,slice 由 Value 值组成,每个返回值作为 slice 中的一个 Value
实际实现功能的 fn 会假设自己的 传入/传出 参数和 typ 传入/传出 参数具有相同的数量和类型
若 typ 描述了一个 可变长参数的 函数,则传入 fn 的 []reflect.Value 的最后一个 Value 值,将用一个 slice 表示所有传入的可变长量
fn 返回的 []reflect.Value 的 Value 值,必须具有 typ 所定义的返回值的数量和类型
对比 reflect.Value 类型的 Call 方法,和 MakeFunc 函数
Value.Call 方法允许调用者传入 reflect.Value 来调用一个函数
MakeFunc 函数允许调用者传入 reflect.Value 来实现一个函数
EG.
package main
import (
"fmt"
"reflect"
)
// PrototypeFunc 函数用于传出函数的最后一个参数值
// 构造一个建立在 MakeFunc 可用的函数
// 该函数将不涉及实际的数据的类型,只有对数据的操作
func PrototypeFunc(in []reflect.Value) (out []reflect.Value) {
// 取得最后一个参数
last := in[len(in)-1]
// 在这里我们可以看到传入数据的类型和值
fmt.Printf("%[1]T\t%[1]v\n", last)
// 数据打包,传出
return []reflect.Value{last}
}
// ValInt 变量用于承载一个只有签名没有实际操作的函数
// 注意使用的是 var 语句,将函数赋予变量,而非函数声明语句
var ValInt func(a, b int, c ...int) []int
func main() {
// 通过 MakeFunc 函数绑定数据操作函数和函数签名
// 生成一个特殊的“原函数”
metaFunc := reflect.MakeFunc(reflect.TypeOf(ValInt), PrototypeFunc)
//获取承载实际函数的变量的指针的 reflect.Value 表示
// 这里取得指针,是为了后面 Set 方法调用
funcValue := reflect.ValueOf(&ValInt)
// 取得指针的 reflect.Value 表示的 指向的值
funcV := funcValue.Elem()
// 将 metaFunc 注入实际运行的函数
funcV.Set(metaFunc)
// 调用实际的函数,并产生最后的结果
fmt.Printf("%v\n", ValInt(1, 2, 3, 4, 5, 6))
}
MakeMap(typ Type) Value
创建一个由指定的类型的元素 组成的 map 的 Value
MapSlice(typ Type, len, cap int) Value
创建一个由指定类型的零值填充的指定长度和容量的 slice 的 Value
New(typ Type) Value
返回一个指向指定类型的零值的指针的 Value
NewAt(typ Type, p unsafe.Pointer) Value
返回一个指向指定类型的零值的指针的 Value
并指定 p 为其指针
ValueOf(i interface{}) Value
返回一个 i 的值所对应的 Value
ValueOf(nil) 将返回 Value 的零值
Zero(typ Type) Value
函数返回代表指定类型的零值的 Value
这和 Value 结构体的零值是不同的概念(Value 的零值表示没有值)
(v Value) Addr() Value
返回 v 的地址的 Value 值
若 CanAddr() 方法返回 false,本方法引发 panic
本函数常用于存储指向 结构体的一个字段的指针 或者 切片的一个元素的指针,
当方法需要 指针 作为接受者的时候,传入方法之中
(v Value) Bool() bool
返回 v 的底层值
若 v 的 kind 并非 Bool,则引发 panic
(v Value) Bytes() []byte
返回 v 的底层值
若 v 的底层值并非 []byte 则引发 panic
(v Value) Call(in []Value) []Value
本方法调用函数 v,并将 in 作为传入参数传入 v 中,函数 v 的返回值作为 []Value 被返回
举例来说,若 len(in)==3,则 v.Call(in) 表示 Go 调用了 v(in[0], in[1], in[2])
若 v 的 Kind 并非 Func,则引发 panic
在 Go 中,每个输入的实参必须可以赋值于对应的形参
若 v 是一个 “可变长函数”,则本方法将可变长参数变为切片,并拷贝对应的值至切片中
(v Value) CallSlice(in []Value) []Value
本方法调用“可变长函数” v,并传入参数 in,将 切片 in[len(in)-1] 作为 函数 v 最后的变长参数 传入,并将返回值作为 []Value 返回
举例来说,若 len(in)==3,则 v.SliceCall(in) 表示 Go 调用了 v(in[0], in[1], in[2]...)
若 v 的 Kind 并非 Func,或 v 并非 “可变长函数”,则引发 panic
在 Go 中,每个输入的实参必须可以赋值于对应的形参
(v Value) CanAddr() bool
报告一个值的地址是否可以被 Addr 方法获得
若可被 Addr 方法持有,则称该值为 可取地址的(addressable)
如果一个值是可取地址的,则表示该值为:
<1> slice 的元素
<2> 可取地址的 array 的元素
<3> 可取地址的 struct 的字段
<4> 解引用后的 pointer
若 CanAddr 返回 false,则调用 Addr 引发 panic
(v Value) CanInterface() bool
报告一个 interface 是否可以不引发 panic 的使用
(v Value) CanSet() bool
报告 v 的值是否可以被改变
一个 Value 可以被改变,仅当该 Value 是 可取的地址的,并且没有被用于 结构体 非导出字段
若 本方法 返回 false,则调用 Set 或任何类型特定的设置方法(eg. SetBool SetInt)会引发 panic
(v Value) Cap() int
返回 v 的容量
若 v 的 Kind 并非 Array Chan Slice,则引发 panic
(v Value) Close()
关闭 通道 v
若 v 的 Kind 并非 Chan,则引发 panic
(v Value) Complex() complex128
以 complex128 的类型,返回 v 的底层值
若 v 的 Kind 并非 Complex64 或 Complex128,则引发 panic
(v Value) Convert(t Type) Value
返回 v 的值转换为 t 的值
若在通常情况下, Go 转换规则不允许 v 转换为 t 类型,则本方法引发 panic
(v Value) Elem() Value
返回 interface v 含有的值,或者 pointer v 指向的值
若 v 的 Kind 并非 Interface 或者 Ptr,则引发 panic
若 v 是 nil,则返回 Value 的 零值
(v Value) Field(i int) Value
返回 struct v 的第 i 个字段
若 v 的 Kind 并非 Struct 或者 i 超出范围,则引发 panic
(v Value) FieldByIndex(index []int) Value
通过指定数组,返回 嵌套结构体 指定的字段值
eg.
package main
import (
"fmt"
"reflect"
)
type A struct {
A1 int
A2 int
B
}
type B struct {
B1 int
C
B2 int
}
type C struct {
C1 int
C2 int
}
func main() {
c := C{4,5}
b := B{2,c,3}
a := A{0,1,b}
va := reflect.ValueOf(a)
fmt.Printf("%v\n", va.FieldByName([]int{2, 1, 1})) // 将返回 5,也就是 结构体 C 的 C2 的值
}
(v Value) FieldByName(name string) Value
寻找指定的字段名名称,返回结构体的字段
若没有找到字段,则返回 Value 的零值
若 v 的 Kind 并非 Struct,则引发 panic
(v Value) FieldByNameFunc(match func(string) bool) Value
用指定的函数匹配字段名名称,返回结构体的字段
若没有找到字段,则返回 Value 的零值
若 v 的 Kind 并非 Struct,则引发 panic
(v Value) Float() float64
以 float64 的类型,返回 v 的底层值
若 v 的 Kind 并非 Float62 或 Float64,则引发 panic
(v Value) Index(i int) Value
返回 v 的 第 i 个元素
若 v 的 Kind 并非 Array Slice String 或 i 超过范围,则引发 panic
(v Value) Int() int64
以 int64 的类型,返回 v 的底层值
若 v 的 Kind 并非 Int Int8 Int16 Int32 或 Int64,则引发 panic
(v Value) Interface() (i interface{})
以 interface{} 的类型,返回当前 v 的值
等价于:
var i interface{} = (v 的底层数据)
若 v 具有的是非导出字段,则引发 panic
(v Value) InterfaceData() [2]unitptr
以 uintptr 对的方式,返回 interface 的值
若 v 的 Kind 并非 Interface,则引发 panic
(v Value) IsNil() bool
报告 v 是否是 nil
v 必须是 chan func interface map pointer slice 中的一种,若不是,引发 panic
注意,IsNil 并不全等于 Go 中普通的 nil 比较
比如:
若 v 是由 对未初始化的 interface 变量 i 取 ValueOf 得到的,则 i==nil 将为真,
但 v.IsNil 将引发 panic,因为 v 是 Value 的零值
(v Value) IsValid() bool
报告 v 是否表示了一个值
若 v 是 Value 的零值,则返回 false
若 IsValid 返回 false,则除了 String 之外的方法都引发 panic
大多数函数和方法从不会返回一个 无效的值
若其中一个可能产生,则它的文档中将有明确的指示
(v Value) Kind() Kind
返回 v 的 Kind
若 v 是 Value 的零值(也就是 IsValid 返回 false), Kind 返回 Invalid
(v Value) Len() int
返回 v 的长度
若 v 的 Kind 并非 Array Chan Map Slice 或 String,则引发 panic
(v Value) MapIndex(key Value) Value
返回 map v 中与键 key 关联的值
若 v 的 Kind 并非 Map,则引发 panic
若不能找到 key,或 v 表示 nil map,本方法返回 Value 的零值
在 Go 中, 键 key 的值必须可以赋予 map 的 键 的 类型
(v Value) MapKeys() []Value
返回一个 slice, 该 slice 具有 v 所表示的 map 的所有的键,顺序未指明
若 v 的 Kind 并非 Map,则引发 panic
若 v 是 nil map,则返回 空 slice
(v Value) Method(i int) Value
返回 v 的第 i 个方法的函数值
使用 返回值 的 Call 方法调用 返回值 对应的方法 时,不应包含接受者,
因为返回值永远使用 v 本身作为接受者
若 i 超出范围,或者 v 表示 nil interface,引发 panic
(v Value) MethodByName(name string) Value
通过方法名返回 v 的方法,
使用 返回值 的 Call 方法调用 返回值 对应的方法 时,不应包含接受者,
因为返回值永远使用 v 本身作为接受者
若未找到方法,则返回 Value 的零值
(v Value) NumField() int
返回 struct v 的总字段数量
若 v 的 Kind 并非 Struct,则引发 panic
(v Value) NumMethod() int
返回 v 的方法集中的方法的总数量
(v Value) OverflowComplex(x complex128) bool
报告 以 complex128 表示的 x 是否能用 v 的类型来表示
若 v 的 Kind 并非 Complex64 或 Complex128,则引发 panic
(v Value) OverflowFloat(x float64) bool
报告 以 float64 表示的 x 是否能用 v 的类型来表示
若 v 的 Kind 并非 Float32 或 Float64,则引发 panic
(v Value) OverflowInt(x int64) bool
报告 以 int64 表示的 x 是否能用 v 的类型来表示
若 v 的 Kind 并非 Int Int8 Int16 Int32 或 Int64,则引发 panic
(v Value) OverflowUint(x uint64) bool
报告 以 uint64 表示的 x 是否能用 v 的类型来表示
若 v 的 Kind 并非 Uint Uintptr Uint8 Uint16 Uint32 或 Uint64,则引发 panic
(v Value) Pointer() uintptr
以 uintptr 的形式返回 v 的值
它返回的是 uintptr 而非 unsafe.Pointer,
这样就保证了,除非明确导入了 unsafe 包,否则代码不可使用 unsafe.Pointer
若 v 的 Kind 并非 Chan Func Map Ptr Slice 或 UnsafePointer,则引发 panic
若 v 的 Kind 是 Func,返回的 pointer 是底层代码的 pointer,但并非确定单个函数的充分条件
仅能保证若结果是 零,那么 v 表示的是 nil func
若 v 的 Kind 是 Slice,返回的 pointer 指向 slice 的第一个元素
若 slice 为 nil,则返回值为 0
若 slice 为空,但并非 nil,则返回的值也非零
(v Value) Recv() (x Value, ok bool)
从 channel v 中接收数据,并将值返回
若 v 的 Kind 并非 Chan,则引发 panic
方法阻塞直到一个值已经准备好被接收
若 x 对应 channel 的 send,则布尔值 ok 为 true
若 x 由于 channel 关闭收到零值,则布尔值 ok 为 false
(v Value) Send(x Value)
向 channel v 中发送 x
若 v 的 kind 并非 Chan 或 x 的类型与 v 的元素的类型不同,则引发 panic
在 Go 中,z 的值必须可以被赋值于 channel 的元素类型
(v Value) Set(x Value)
将 x 赋予值 v 中
若 CanSet 返回 false,则引发 panic
在 Go 中,x 的值必须可以被赋值于 v 的类型
(v Value) SetBool(x bool)
设置 v 的底层值
若 v 的 Kind 并非 Bool 或者 CanSet() 返回 false,则引发 panic
(v Value) SetBytes(x []byte)
设置 v 的底层值
若 v 的底层值并非 []byte,则引发 panic
(v Value) SetCap(n int)
设置 v 的容量至 n
若 v 的 Kind 不为 Slice 或 n 比 slice 的长度小,或者比 slice 的容量大,都会引发 panic
(v Value) SetComplex(x complex128)
设置 v 的底层值
若 v 的 Kind 并非 Complex64 或 Complex128 或 CanSet() 返回 false,都会引发 panic
(v Value) SetFloat(x float64)
设置 v 的底层值
若 v 的 Kind 并非 Float32 或 Float64,或 CanSet() 返回 false,都会引发 panic
(v Value) SetInt(x int64)
设置 v 的底层值
若 v 的 Kind 并非 Int Int8 Int16 Int32 或 Int64,或 CanSet() 返回 false,都会引发 panic
(v Value) SetLen(n int)
设置 v 的长度至 n
若 v 的 Kind 并非 Slice 或 n 是负值,或者比 slice 的容量大,都会引发 panic
(v Value) SetMapIndex(key, val Value)
将 map 的中 key 对应的键的键值设置为 val
若 v 的 Kind 并非 Map,则引发 panic
若 val 为 Value 的零值,则 本方法从 map 中删除 key 对应的键值对
若 v 持有 nil map,则引发 panic
在 Go 中,key 的值必须可以被赋值于 map 的键类型,val 的值必须可以被赋予 map 的值类型
(v Value) SetPointer(x unsafe.Pointer)
将 unsafe.Pointer x 的值设置至 v 中
若 v 的 Kind 并非 UnsafePointer,则引发 panic
(v Value) SetString(x string)
设置 v 的底层值
若 v 的 Kind 并非 String 或 CanSet() 返回 false,都会引发 panic
(v Value) SetUint(x int64)
设置 v 的底层值
若 v 的 Kind 并非 Uint Uintptr Uint8 Uint16 Uint32 或 Uint64,或 CanSet() 返回 false,都会引发 panic
(v Value) Slice(i, j int) Value
返回 v[i:j]
若 v 的 Kind 并非 Array Slice 或 String,或 v 是一个 不可取地址的 array,或 索引超出范围,都会引发 panic
(v Value) Slice3(i, j, k int) Value
本方法为 三索引形式 的 切片 操作:也就是返回 v[i:j:k]
若 v 的 Kind 并非 Array Slice 或 String,或 v 是一个 不可取地址的 array,或 索引超出范围,都会引发 panic
(v Value) String() string
返回 v 的底层值的字符串表示
由于 Go 的 String 方法的便利性,本方法是一种特殊情况
不像其他的取值方法,若 v 的 Kind 不为 String,本方法也不会产生 panic
相反,它会以如下形式返回一个字符串: "<T value>",其中 T 是 v 的类型
fmt 包特殊对待 Value 类型的值
它并不会隐式地调用 Value 类型的值的 String 方法,而是打印它们所具有的底层值
(v Value) TryRecv() (x Value, ok bool)
本方法尝试从 channel v 中接收一个值,但不会产生阻塞
若 v 的 Kind 并非 Chan,则引发 panic
若 channel 发出了一个值,x 传出那个值, ok 为 true
若 接收操作不能再不阻塞的情况下完成,则 x 为 Value 的零值, ok 为 false
若 channel 关闭,则 x 为 channel 元素的零值,ok 为 false