开源一个小工具structmapper

535 阅读1分钟

实际项目开发中,需要各个层的数据流转,entity转换到domain,domain转换到response,常见实现的方式基本都是通过反射机制实现,例如Spring BeanUtils. copyProperties,Golang的copier第三方库,反射的效率众所周知,基本都是惨不忍睹。

当然也可以手动一个个的赋值

type User struct {
   ID int
   Mobile       string
   Level       int
   Name           string
   RegisterTime time.Time
}

func (u *User) Mapping (from *User) {
    u.ID = from.ID
    u.Mobile = from.Mobile
    u.Level = from.Level
    u.Name = from.Name
    u.RegisterTime = from.RegisterTime
}

对比一下手动赋值和反射的效率

## Benchmarks

| Benchmark name                 |       (1) |             (2) |          (3) |             (4) |
| ------------------------------ | ---------| ---------------| ------------| ---------------|
| BenchmarkMapper         | 1000000000 | 0.3679 ns/op |   0 B/op | 0 allocs/op |
| BenchmarkCopier         |     163282 |     6852 ns/op |       3000 B/op  |     48 allocs/op |

反射每次耗时6852ns,手动赋值0.36ns,效率差距还是巨大的。

structmapper小工具因此应运而生,structmapper是通过 go:generate 自动生成Mapping函数。

//go:generate go run github.com/wizardshan/structmapper -toName User -fromName User -toPath ./response  -fromPath ./domain -toVar resp -fromVar dom
//go:generate go run github.com/wizardshan/structmapper -toName Orders -fromName Orders -toPath ./response  -fromPath ./domain -toVar resp -fromVar dom

package response

type User struct {
    ID int `json:"id"`
    CreateTime DateTime `json:"createTime"`
    UpdateTime *DateTime `json:"updateTime"`
    DeleteTime *DateTime `json:"deleteTime"`
    Mobile string `json:"mobile"`
    Nickname string `json:"nickname"`
    Money Money `json:"money"`
    Level int `json:"level"`
}

package domain

type User struct {
    ID int
    CreateTime time.Time
    UpdateTime *time.Time
    Mobile string
    Nickname string
    Money int
}

func (dom *User) Level() int {
	return 1
}

user_mapping.go
func (resp *User) Mapping(dom *domain.User) {
	/**************** mapping start ****************/
	resp.ID = dom.ID
	resp.CreateTime = DateTime(dom.CreateTime)
	if dom.UpdateTime != nil {
		updateTime := DateTime(*dom.UpdateTime)
		resp.UpdateTime = &(updateTime)
	}

	//resp.DeleteTime = fromStruct property not exist
	resp.Mobile = dom.Mobile
	resp.Nickname = dom.Nickname
	resp.Money = Money(dom.Money)
	resp.Level = dom.Level()

	/**************** mapping end  ****************/
}

希望大家多提意见 项目地址