-
需求:一般情况下我们都会自定义一个结构体来接收请求体而不是直接使用模型结构体来接收数据,因为模型中一些字段时不允许前端来输入的。但是这样就会出现一些小问题:如果字段很多的话赋值是个体力活
updTag.png
方案提供:
- 序列化&反序列化
// DataCopy 本来想使用reflect包来完成这个功能,json.Marshal()其实也是借助reflect包来实现的.
// TIP: 少于五个字段不建议使用
func DataCopy(data, res interface{}) error {
b, err := json.Marshal(data)
if err != nil {
return err
}
return json.Unmarshal(b, res)
}
- 反射包实现
package main
import (
"fmt"
"reflect"
)
type Per struct {
Name string
Age int
Gender int
Add string
}
type Stu struct {
Name string
Age int
Gender int
Test string
}
func (s *Stu) Create() {
fmt.Printf("student %s created!\n", s.Name)
fmt.Printf("%#v", s) // main.Stu{Name:"casso", Age:23, Gender:3, Test:""}
}
// DataReflact 传入*reflect.Value 且返回 *reflect.Value ,将类型交给调用者来决定。
func DataReflact(src, dst *reflect.Value) *reflect.Value {
for i := 0; i < src.NumField(); i++ {
filed := src.Type().Field(i).Name
cfiled := dst.FieldByName(filed)
if cfiled.IsValid() && cfiled.CanSet() { // 可用的属性且可赋值
dst.Field(i).Set(src.Field(i))
}
}
return dst
}
func main() {
data := Per{
Name: "casso",
Age: 23,
Gender: 3,
Add: "testAadd", // 多余的/Stu不存在的字段是不会强加给Stu的
}
container := Stu{}
// 使用着三行代替繁琐的挨个赋值
src := reflect.ValueOf(&data).Elem()
dst := reflect.ValueOf(&container).Elem()
newStu := DataReflact(&src, &dst).Interface().(Stu)
fmt.Println(reflect.TypeOf(newStu)) // main.Stu
newStu.Create() // student casso created!
}
- 关于第二个方案
src := reflect.ValueOf(&data).Elem()
dst := reflect.ValueOf(&container).Elem()
这两行本来是想放到DataReflact方法里面解决的,但是如果方法入参改为interface{}的话,经过转换Stu的字段是不可寻址的,无法赋值。
