func (orm *Model) ScanPK(output interface{}) *Model { if reflect.TypeOf(reflect.Indirect(reflect.ValueOf(output)).Interface()).Kind() == reflect.Slice { sliceValue := reflect.Indirect(reflect.ValueOf(output)) sliceElementType := sliceValue.Type().Elem() for i := 0; i < sliceElementType.NumField(); i++ { bb := sliceElementType.Field(i).Tag if bb.Get("beedb") == "PK" || reflect.ValueOf(bb).String() == "PK" { orm.PrimaryKey = sliceElementType.Field(i).Name } } } else { tt := reflect.TypeOf(reflect.Indirect(reflect.ValueOf(output)).Interface()) for i := 0; i < tt.NumField(); i++ { bb := tt.Field(i).Tag if bb.Get("beedb") == "PK" || reflect.ValueOf(bb).String() == "PK" { orm.PrimaryKey = tt.Field(i).Name } } } return orm }
开始看谢大的beedb,结果在Model.ScanPk(interface{})
就卡住了,主要是对函数中一些反射相关的API不了解,那就从反射开始研究吧。
先来介绍ScanPK
中会涉及到的几个数据结构,这里只会写到跟这个函数相关的数据结构的相关字段,如果有兴趣进一步研究的话请移步golang reflect
- Type 表示数据结构类型的数据结构,部分字段的声明如下:
type Type interface { // 这个Type的种类 Kind() Kind // 查找这个Type的第 i 个字段 Field(i int) StructField // 字段的数量 NumField() int }
-
Value 表示数据结构值的数据结构,部分字段的声明如下:
-
Kind Go语言内置类型的枚举值,声明如下:
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 )
- StructField 用于描述一个数据结构的字段,部分字段声明如下:
type StructField struct { // 这个字段的名字 Name string Tag StructTag // 这个字段的注释 }
- StructTag StructField中有一个Tag字段,这个字段是对所属字段属性的一种补充。比如现在有一个自定义的数据结构声明如下:
type Person struct { Name string `json:"name"` Age int }
与C语言不同的地方是,Name字段在声明后,又添加了一段被反引号(`)包围的字符串,这个字符串的规则是键名:"值"
。那么这种类型的结构在被反射时,这段被包围的字符串便会被解析到StructTag
中,可以使用函数StructTag.Get(key string)
来获得某个值。
到这里,需要用到的数据结构就都交代完毕了,其中最重要的两个数据结构是Value、Type
,一个表示值,一个表示类型。接下来再看几个函数。
有疑问加站长微信联系(非本文作者)