Automatically generate conversion code based on function type declarations, supporting conversion/deep copy modes, and custom conversion functions/filters/ignore specific fields and other options.
- Support conv/deepCopy modes
- Support generics
- Support automatic pointer resolution
- Support basic types/map/slice/array/struct conversion
- Support automatic upcasting of basic types
- Support Alias type automatic conversion
- Support embed field automatic unpacking
- Support self-referencing objects, support recursive conversion
- Automatically handle naming conflicts in the same package
- Support string <-> []byte/[]rune conversion
- Support Pointer <-> Struct conversion
- Support Array <-> Slice conversion
- Support extended custom conversion/filter/ignore options
Generation command:
go run github.com/ycl2018/go-conv@latest./...
The conv mode is the default type conversion mode, which uses shallow copy to improve conversion performance.
// go-conv:generate
var Foo2Bar func (src *Foo) *Bar
type Foo struct {
Str string
Slice []string
Map map[string]string
Pointer string
Alias string
}
type Bar struct {
Str string
Slice []string
Map map[string]string
Pointer *string
Alias StringAlias
}
type StringAlias string
generated:
// Code generated by github.com/ycl2018/go-conv DO NOT EDIT.
package testdata
func FooToBar(src *Foo) (dst *Bar) {
if src!= nil {
dst = new(Bar)
dst.Str = src.Str
dst.Slice = src.Slice
dst.Map = src.Map
dst.Pointer = &src.Pointer
dst.Alias = (StringAlias)(src.Alias)
}
return
}
func init() {
Foo2Bar = FooToBar
}
The copy mode uses a deep copy mode to copy each field of the structure.
// go-conv:generate
// go-conv:copy
var Foo2Bar func(src *Foo) *Bar
type Foo struct {
Str string
Slice []string
Map map[string]string
Pointer string
Alias string
}
type Bar struct {
Str string
Slice []string
Map map[string]string
Pointer *string
Alias StringAlias
}
type StringAlias string
generated:
// Code generated by github.com/ycl2018/go-conv DO NOT EDIT.
package example
func CopyPtrFooToPtrBar(src *Foo) (dst *Bar) {
if src!= nil {
dst = new(Bar)
dst.Str = src.Str
if len(src.Slice) > 0 {
dst.Slice = make([]string, len(src.Slice))
for i := 0; i < len(src.Slice); i++ {
dst.Slice[i] = src.Slice[i]
}
}
if len(src.Map) > 0 {
dst.Map = make(map[string]string, len(src.Map))
for k, v := range src.Map {
var tmpK string
var tmpV string
tmpK = k
tmpV = v
dst.Map[tmpK] = tmpV
}
}
dst.Pointer = new(string)
*dst.Pointer = src.Pointer
dst.Alias = StringAlias(src.Alias)
}
return
}
func init() {
Foo2Bar = CopyPtrFooToPtrBar
}
You can use go-conv:apply to specify the configuration to be applied, which is programmatically IDE-friendly and more convenient to configure.
package cases
import (
"strconv"
"github.com/ycl2018/go-conv/option"
"github.com/ycl2018/go-conv/testdata/a"
"github.com/ycl2018/go-conv/testdata/b"
)
// Struct2Struct conv a Basic to b Basic
// go-conv:generate
// go-conv:apply basicConvOpts
var Struct2Struct func(p *a.Struct) *b.Struct
var basicConvOpts = []option.Option{
option.WithIgnoreFields(a.Struct{}, []string{"Pojo"}),
option.WithIgnoreTypes(a.Student{}, "Student3"),
option.WithTransformer(transfer, "Student2.Class.Grade"),
option.WithFilter(filter, "Student2.Teachers"),
option.WithFieldMatch(a.Struct{}, map[string]string{
"Match": "Match_",
}),
option.WithMatchCaseInsensitive(),
option.WithNoInitFunc(),
}
func transfer(t int) string {
return strconv.Itoa(t)
}
func filter(arr []string) []string {
return arr
}
// Code generated by github.com/ycl2018/go-conv DO NOT EDIT.
package cases
import (
"github.com/ycl2018/go-conv/testdata/a"
"github.com/ycl2018/go-conv/testdata/b"
)
func PtrAStructToPtrBStruct(src *a.Struct) (dst *b.Struct) {
if src!= nil {
dst = new(b.Struct)
dst.Student.Name = src.Student.Name
dst.Student.Class.Name = src.Student.Class.Name
dst.Student.Class.Grade = string(src.Student.Class.Grade)
dst.Student.Teachers = src.Student.Teachers
dst.Student2.Name = src.Student2.Name
dst.Student2.Class.Name = src.Student2.Class.Name
// apply transfer option on transfer
transferredSrcStudent2ClassGrade := transfer(src.Student2.Class.Grade)
dst.Student2.Class.Grade = transferredSrcStudent2ClassGrade
// apply filter option on filter
filteredSrcStudent2Teachers := filter(src.Student2.Teachers)
dst.Student2.Teachers = filteredSrcStudent2Teachers
// apply ignore option on src.Student3
// apply ignore option on src.Pojo
dst.Match_ = src.Match
dst.Caseinsensitive = src.CaseInsensitive
}
return
}