开发中会频繁的使用各种对象,在Java中称为Javabean,在Go中用结构体。使用ORM框架时,经常会用实体类来映射数据表,但实际上很少会直接使用映射数据表的实体类对象在各层传输,更多的会使用其他对象(如DTO,VO等),对读出的实体类对象的属性进行过滤或增加。
copy()copy()
不过Go自带反射包,利用反射,我们可以手动实现一个任意类型属性拷贝的函数或方法。
实现起来也很简单,喜欢琢磨的朋友可以直接阅读反射的文档自己实现。
golang.org/pkg/reflect…
Overview
以下摘自文档
Package reflect implements run-time reflection, allowing a program to manipulate objects with arbitrary types. The typical use is to take a value with static type interface{} and extract its dynamic type information by calling TypeOf, which returns a Type.
A call to ValueOf returns a Value representing the run-time data. Zero takes a Type and returns a Value representing a zero value for that type.
TypeOfTypeValueOfValue
reflect
Kind
type Kind uint
iotaKindKindStrcutKindPtrSliceMapArrrayChan
ValueTypeTypeMapOf()MapTypeMappanicpanic()Kind
Type
Typereflect.TypeOf(i interface{})
Name()Kind()Kind
KindStructNumField()Field(i int) StructFieldFieldByName(name string) StructFieldStructField
KindArrayChanMapPtrSliceElem()Type
panic()
Type
StructField
用来描述结构体中单个属性,定义如下
type StructField struct {
Name string
PkgPath string
Type Type
Tag StructTag
Offset uintptr
Index []int
Anonymous bool
}
复制代码
NamePkgPathTypeTag
Value
TypeValuereflect.ValueOf(i interface{})TypeValueValueTypeNumField()Field(i)FieldByName(name string)Elem()
Value
TypeValue
panic()
实践
上文简单了解了一下反射的基础。相信很多人都知道怎么实现了。
Field(i int)StuctFieldNameNameFieldByName(name string)Set(v Value)
coding
func SimpleCopyProperties(dst, src interface{}) (err error) {
// 防止意外panic
defer func() {
if e := recover(); e != nil {
err = errors.New(fmt.Sprintf("%v", e))
}
}()
dstType, dstValue := reflect.TypeOf(dst), reflect.ValueOf(dst)
srcType, srcValue := reflect.TypeOf(src), reflect.ValueOf(src)
// dst必须结构体指针类型
if dstType.Kind() != reflect.Ptr || dstType.Elem().Kind() != reflect.Struct {
return errors.New("dst type should be a struct pointer")
}
// src必须为结构体或者结构体指针
if srcType.Kind() == reflect.Ptr {
srcType, srcValue = srcType.Elem(), srcValue.Elem()
}
if srcType.Kind() != reflect.Struct {
return errors.New("src type should be a struct or a struct pointer")
}
// 取具体内容
dstType, dstValue = dstType.Elem(), dstValue.Elem()
// 属性个数
propertyNums := dstType.NumField()
for i := 0; i < propertyNums; i++ {
// 属性
property := dstType.Field(i)
// 待填充属性值
propertyValue := srcValue.FieldByName(property.Name)
// 无效,说明src没有这个属性 || 属性同名但类型不同
if !propertyValue.IsValid() || property.Type != propertyValue.Type() {
continue
}
if dstValue.Field(i).CanSet() {
dstValue.Field(i).Set(propertyValue)
}
}
return nil
}
复制代码
小结
reflectpanicrecoverpanicSliceMap
反射包中还有很多有意思的东西,感兴趣的朋友可以参考文档。
golang.org/pkg/reflect…