Copier for golang, copy value from struct to struct and more

Overview

Copier

I am a copier, I copy everything from one to another

test status

Features

  • Copy from field to field with same name
  • Copy from method to field with same name
  • Copy from field to method with same name
  • Copy from slice to slice
  • Copy from struct to slice
  • Copy from map to map
  • Enforce copying a field with a tag
  • Ignore a field with a tag
  • Deep Copy

Usage

package main

import (
	"fmt"
	"github.com/jinzhu/copier"
)

type User struct {
	Name string
	Role string
	Age  int32

	// Explicitly ignored in the destination struct.
	Salary   int
}

func (user *User) DoubleAge() int32 {
	return 2 * user.Age
}

// Tags in the destination Struct provide instructions to copier.Copy to ignore
// or enforce copying and to panic or return an error if a field was not copied.
type Employee struct {
	// Tell copier.Copy to panic if this field is not copied.
	Name      string `copier:"must"`

	// Tell copier.Copy to return an error if this field is not copied.
	Age       int32  `copier:"must,nopanic"`

	// Tell copier.Copy to explicitly ignore copying this field.
	Salary    int    `copier:"-"`

	DoubleAge int32
	EmployeId int64
	SuperRole string
}

func (employee *Employee) Role(role string) {
	employee.SuperRole = "Super " + role
}

func main() {
	var (
		user      = User{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 200000}
		users     = []User{{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 100000}, {Name: "jinzhu 2", Age: 30, Role: "Dev", Salary: 60000}}
		employee  = Employee{Salary: 150000}
		employees = []Employee{}
	)

	copier.Copy(&employee, &user)

	fmt.Printf("%#v \n", employee)
	// Employee{
	//    Name: "Jinzhu",           // Copy from field
	//    Age: 18,                  // Copy from field
	//    Salary:150000,            // Copying explicitly ignored
	//    DoubleAge: 36,            // Copy from method
	//    EmployeeId: 0,            // Ignored
	//    SuperRole: "Super Admin", // Copy to method
	// }

	// Copy struct to slice
	copier.Copy(&employees, &user)

	fmt.Printf("%#v \n", employees)
	// []Employee{
	//   {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeId: 0, SuperRole: "Super Admin"}
	// }

	// Copy slice to slice
	employees = []Employee{}
	copier.Copy(&employees, &users)

	fmt.Printf("%#v \n", employees)
	// []Employee{
	//   {Name: "Jinzhu", Age: 18, Salary:0, DoubleAge: 36, EmployeId: 0, SuperRole: "Super Admin"},
	//   {Name: "jinzhu 2", Age: 30, Salary:0, DoubleAge: 60, EmployeId: 0, SuperRole: "Super Dev"},
	// }

 	// Copy map to map
	map1 := map[int]int{3: 6, 4: 8}
	map2 := map[int32]int8{}
	copier.Copy(&map2, map1)

	fmt.Printf("%#v \n", map2)
	// map[int32]int8{3:6, 4:8}
}

Copy with Option

copier.CopyWithOption(&to, &from, copier.Option{IgnoreEmpty: true, DeepCopy: true})

Contributing

You can help to make the project better, check out http://gorm.io/contribute.html for things you can do.

Author

jinzhu

License

Released under the MIT License.

Issues
  • fix:sql.NullInt32 to int32 and sql.NullByte to byte error

    fix:sql.NullInt32 to int32 and sql.NullByte to byte error

    type A struct {
    	Id sql.NullInt32
    }
    
    type B struct {
    	Id int32
    }
    
    func main() {
    	var a A
    	var b B
    	a = A{Id: sql.NullInt32{Int32: 233, Valid: true}}
    	_ = copier.Copy(&b, a)
    	fmt.Println(a)
    	fmt.Println(b)
    }
    

    the code output is。b.Id not set value

    {{233 true}}
    {0}
    

    Because the value method of sql.NullInt32will convert int32 to Int64。sql.NullInt16 and sql.NullByte are the same

    func (n NullInt32) Value() (driver.Value, error) {
    	if !n.Valid {
    		return nil, nil
    	}
    	return int64(n.Int32), nil
    }
    

    It is false to judge whether the value can be assigned

     if rv.Type().AssignableTo(to.Type()) {
    			to.Set(rv)
    		}
    

    So I added a judgment. If the data is of type int, first convert it to the corresponding type for assignment

    if strings.HasPrefix(rv.Type().String(), "int") && (strings.HasPrefix(to.Type().String(), "int") || strings.HasPrefix(to.Type().String(), "uint")) {
    			convert := rv.Convert(to.Type())
    			to.Set(convert)
    		} else if rv.Type().AssignableTo(to.Type()) {
    			to.Set(rv)
    		}
    
    opened by jiang4869 7
  • [Bug] Copy time.Time not working

    [Bug] Copy time.Time not working

    Reproducible Example

    https://play.golang.org/p/pbA2Z1XJotV

    Description

    Hi everyone,

    I'm not abble to copy structure of type time.Time. See the example above.

    Thanks in advance @jinzhu @math-nao

    opened by maeglindeveloper 7
  • Nested Slice getting copied by reference.

    Nested Slice getting copied by reference.

    Issue demonstrated in following code snippet.

    package main
    
    import (
    	"fmt"
    	"github.com/jinzhu/copier"
    )
    
    type A struct {
    	X []int
    }
    
    type B struct {
    	X []int
    }
    
    func main() {
    	x := []int{1, 50}
    	a := A{X: x}
    	b := B{}
    	copier.Copy(&b, a)
    	fmt.Printf("X0 in B %v %v\n", b.X[0], b.X[1]) // Returns 1
    	fmt.Printf("X0 in A %v %v\n", a.X[0], a.X[1]) // Returns 1
    	a.X[0] = -1
    	a.X[1] = -50
    	fmt.Printf("X in B %v %v\n", b.X[0], b.X[1]) // Returns -1
    	fmt.Printf("X in A %v %v\n", a.X[0], a.X[1]) // Returns -1
    }
    
    
    opened by bhupkasUber 7
  • Copy with nested pointer to struct causes panic

    Copy with nested pointer to struct causes panic

    The following code causes a panic:

    package main
    
    import "github.com/jinzhu/copier"
    
    func main() {
    	type nested struct {
    		A string
    	}
    	type parentA struct {
    		*nested
    	}
    	type parentB struct {
    		*nested
    	}
    	a := parentA{nested: &nested{A: "a"}}
    	b := parentB{}
    
    	copier.Copy(&b, &a)
    }
    
    

    stack trace:

    $ go run copier_panic.go
    panic: reflect: indirection through nil pointer to embedded struct
    
    goroutine 1 [running]:
    reflect.Value.FieldByIndex(0x4d4fe0, 0xc04206e020, 0x199, 0xc0420500d0, 0x2, 0x2, 0x0, 0x568f40, 0x4c8a00)
            C:/tools/go/src/reflect/value.go:804 +0x276
    reflect.Value.FieldByName(0x4d4fe0, 0xc04206e020, 0x199, 0x4b5ea6, 0x1, 0x4c8a00, 0xc042044250, 0x198)
            C:/tools/go/src/reflect/value.go:820 +0x16e
    github.com/jinzhu/copier.Copy(0x4c2a60, 0xc04206e020, 0x4c2a20, 0xc04206e018, 0x0, 0x0)
            E:/workspace/golang/src/github.com/jinzhu/copier/copier.go:71 +0x491
    main.main()
            E:/workspace/golang/src/playground/copier_panic.go:18 +0xb1
    exit status 2
    

    The issue originates from this: https://github.com/jinzhu/copier/blob/db4671f3a9b8df855e993f7c94ec5ef1ffb0a23b/copier.go#L71

    Is this something that can be fixed in copier? I don't know enough about reflection but if you can guide me, I can make a PR to fix this.

    opened by sudo-suhas 7
  • [Bug] Panic on SetMapIndex when using map[x]interface{}

    [Bug] Panic on SetMapIndex when using map[x]interface{}

    Reproducible Example

    https://play.golang.org/p/RJOgBhY1oGo

    Description

    Hi everyone,

    I'm facing again a panic using the CopyWithOptions() method. See above the example.

    It seems this is related to map[x]interface{} @jinzhu

    opened by maeglindeveloper 4
  • [Bug] crashed with nested struct

    [Bug] crashed with nested struct

    Reproducible Example

    https://play.golang.org/p/INvrWLUd6BD

    code samples

    package main
    
    import (
    	"github.com/jinzhu/copier"
    )
    
    func main() {
    	type Basic struct {
    		ID   int
    		Name string
    		Addr string
    	}
    
    	type S struct {
    		Basic
    		Level int
    	}
    
    	s1 := S{}
    
    	var s2 S
    	copier.Copy(&s2, s1)
    
    }
    
    

    Description

    Crashed with nested struct. seemed cause by copier.go+193.

    if f, ok := dest.Type().FieldByName(name); ok {
    for idx, x := range f.Index {
    	destFieldKind := dest.Field(x).Kind()
    

    as mentioned by: https://golang.org/pkg/reflect/#StructField

    " Index []int // index sequence for Type.FieldByIndex ", the index can't used by dest.Field(x)

    opened by tubzby 4
  • Full support sql.Null* structs on both sides. Copy to Scanner interface and from Valuer interface.

    Full support sql.Null* structs on both sides. Copy to Scanner interface and from Valuer interface.

    Right copy of:

    sql.Null* -> generic types

    • sql.NullString -> string
    • sql.NullTime -> time.Time
    • etc...

    sql.Null* -> ptr to generic types

    • sql.NullString -> *string
    • etc...

    Or vice versa:

    generic types -> sql.Null*

    • string -> sql.NullString
    • time.Time -> sql.NullTime
    • etc...

    ptr to generic types -> sql.Null*

    • *string -> sql.NullString
    • *time.Time -> sql.NullTime
    • etc...

    Totally covered by tests.

    opened by timsolov 4
  • Copy map with slice-type value panic

    Copy map with slice-type value panic

    Reproducible Example

    fromMap := make(map[string][]int32)
    slice := []int32{1, 2}
    fromMap["key1"] = slice
    toMap := make(map[string][]int32)
    copier.Copy(&toMap, fromMap)
    

    Description

    copy a map which has slice-type value will report error: reflect.Value.Addr of unaddressable value

    opened by studentliying 3
  • Copy un-exported struct fields in DeepCopy

    Copy un-exported struct fields in DeepCopy

    This should fix issues #97 and #98. Like PR #105, it is not specific to time.Time, but resolves the issue by ensuring un-exported fields of a struct are copied, even when DeepCopy: true.

    The idea was inspired by PR #105, but the structure is quite different. PR #105 did not resolve the issue I faced or make tests pass. This PR does both.

    I retained the tests added by PRs #103 and #105 and added a few more cases that exhibit the specific issue I faced.

    opened by joshhardy 3
  • fix copy same struct with pointer fields

    fix copy same struct with pointer fields

    fix a bug, when we're copying the same struct which has pointer fields, we'll get the same address of pointer field on original and new one after copy. After this fix, it will be ok!

    opened by hothero 3
  • Struct with pointers

    Struct with pointers

    At the moment I am unable to copy struct A to struct B. It does not copy because this check: fromField.Type().AssignableTo(toField.Type()) on line 73 returns false. It is false because fromField type is *string and toField type is string. Is it possible to copy these two kind of structs?

    type A struct {
        Title *string
        Description *string
        Status *bool
    }
    
    type B struct {
        Title string
        Description string
        Status bool
    }
    
    opened by martijn-dd 3
  • fix: type converter for interface types

    fix: type converter for interface types

    TL;DR

    This PR makes it possible to use custom type converters on interface types. It works by resolving interfaces to concrete types before the conversion takes place.


    It seems to be impossible to define use interface types for SrcType or DstType of the type converter. Internally the copier will resolve these types to the actual underlying types, because of how reflect.TypeOf works, e.g.:

    type MyI interface{ A() }
    type MyS struct{}
    func (MyS) A() {}
    
    var m MyI = MyS{}
    fmt.Println(reflect.TypeOf(m))  // prints: MyS
    

    When the copier encounters a struct field with an interface type, it then wouldn't know what type converter to use. This PR fixes this issue, so that this actually works:

    package main
    
    import (
    	"fmt"
    
    	"github.com/jinzhu/copier"
    )
    
    type Logger interface {
    	LogAction(string)
    }
    
    type EmployeeLogger struct {
    	Level string
    }
    
    func (l *EmployeeLogger) LogAction(action string) {}
    
    type Employee struct {
    	Logger Logger
    }
    
    func main() {
    	employee := Employee{Logger: &EmployeeLogger{Level: "debug"}}
    	converters := []copier.TypeConverter{
    		copier.TypeConverter{
    			SrcType: &EmployeeLogger{},
    			DstType: &EmployeeLogger{},
    			Fn: func(src interface{}) (interface{}, error) {
    				return &EmployeeLogger{Level: src.(*EmployeeLogger).Level + "-xxx"}, nil
    			},
    		},
    	}
    
    	copy := Employee{}
    	copier.CopyWithOption(&copy, &employee, copier.Option{Converters: converters})
    	fmt.Println(copy.Logger.(*EmployeeLogger).Level) // prints: debug-xxx
    }
    
    opened by aisbergg 0
  • DeepCopy tag?

    DeepCopy tag?

    Hi @jinzhu ,

    In my case I would like to deepcopy all nested fields, except some pointers. I looked at the code but it does not seem there is a tag to prevent or force the deepcopy for a specific field. Do you confirm?

    Thank you,

    opened by sneko 0
  • Copy didn't success, error should be returned

    Copy didn't success, error should be returned

    Unsuccessful copy, expected error return

    	src := struct{ Name string }{Name: "harrison"}
    	dst := make(map[string]interface{})
    
    	err := copier.CopyWithOption(&dst, src, copier.Option{DeepCopy: true})
    	if err != nil { // if copy didn't success, error should be returned
    		panic(err)
    	}
    
    	fmt.Println(dst) // empty map
    

    Description

    https://goplay.tools/snippet/ra4iaMjkHnl

    opened by harrisonho99 0
  • Doesn't deep-copy structs provided via pointers

    Doesn't deep-copy structs provided via pointers

    	var user *User = &User{Name: "Jinzhu", Age: 18, Role: "Admin", Salary: 200000}
    	var newUser *User
    	err := copier.CopyWithOption(&newUser, &user, copier.Option{DeepCopy: true})
    

    Gives copy destination is invalid error.

    https://goplay.tools/snippet/ITQqvdUwKWH

    opened by bryndin 2
Owner
Jinzhu
Life is Art
Jinzhu
read copy update map for golang 1.18+

(R)ead-(C)opy-Update read copy update map for golang 1.18+ How it works This is a simple generic implementation for https://en.wikipedia.org/wiki/Read

Michael Ernst 11 Mar 30, 2022
Steampipe plugin to query your Scalingo apps, addons and more

Scalingo plugin for Steampipe Use SQL to query infrastructure including applications and addons from Scalingo. Get started → Documentation: Table defi

François de Metz 9 Nov 23, 2021
💪 Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more.

?? Helper Utils For The Go: string, array/slice, map, format, cli, env, filesystem, test and more. Go 的一些工具函数,格式化,特殊处理,常用信息获取等等

Gookit 839 Jun 29, 2022
F - Experimenting with Go 1.18 generics to write more functional Go code

f f is a simple library that leverages the new generics in Golang to create a tools for functional style of code. Pipe like '|>' in Elixir or Elm. inp

Amirreza Askarpour 3 Apr 12, 2022
Leftright - A concurrent map that is optimized for scenarios where reads are more frequent than writes

leftright A concurrent map that is optimized for scenarios where reads are more

Yang Pan 1 Jan 30, 2022
Utility package that provides the ability to more conveniently work with URL parameters.

Utility package that provides the ability to more conveniently work with URL parameters.

Radik Khisamutdinov 1 Feb 8, 2022
Tugas Alta Immersive Backend Golang Fundamental Programming (Pointer, Struct, Method, Interface)

Tatacara Melakukan Setup Tugas clone project ini dengan cara git clone https://github.com/Immersive-Backend-Resource/Pointer-Struct-Method-Interface.g

null 0 Jan 9, 2022
reflect api without runtime reflect.Value cost

reflect2 reflect api that avoids runtime reflect.Value cost reflect get/set interface{}, with type checking reflect get/set unsafe.Pointer, without ty

Modern Go Programming 574 Jun 24, 2022
Helm plugin to reference value files packaged in dependency charts

Helm Octopus Plugin This Helm plugin allows to reference packaged value files (other than the default values.yaml). Install helm plugin install https:

Softonic 3 Sep 23, 2021
Robust & Easy to use struct mapper and utility methods for Go

go-model Robust & Easy to use model mapper and utility methods for Go struct. Typical methods increase productivity and make Go development more fun ?

Jeevanandam M. 351 Jun 19, 2022
A Runtime Struct Builder for Go

A Runtime Struct Builder for Go

null 32 May 7, 2022
Go tool to modify struct field tags

Go tool to modify/update field tags in structs. gomodifytags makes it easy to update, add or delete the tags in a struct field. You can easily add new tags, update existing tags (such as appending a new key, i.e: db, xml, etc..) or remove existing tags

Fatih Arslan 1.8k Jul 1, 2022
Go linter to check the struct literal to use field name

Structfield Find struct literals using non-labeled fields. The structfield analysis reports the usage of struct literal using non-labeled fields more

Nuruddin Ashr 3 Aug 23, 2021
gin struct controller

gin struct controller

null 1 Oct 4, 2021
Highly configurable struct to map converter.

Mapify Highly configurable struct to map converter. Will convert maps into other maps as well (work in progress). Features configuration outside the s

Jacek Olszak 3 Mar 4, 2022
Goridge is high performance PHP-to-Golang codec library which works over native PHP sockets and Golang net/rpc package.

Goridge is high performance PHP-to-Golang codec library which works over native PHP sockets and Golang net/rpc package. The library allows you to call Go service methods from PHP with a minimal footprint, structures and []byte support.

Spiral Scout 1.1k Jun 24, 2022
A Go (golang) library for parsing and verifying versions and version constraints.

go-version is a library for parsing versions and version constraints, and verifying versions against a set of constraints. go-version can sort a collection of versions properly, handles prerelease/beta versions, can increment versions, etc.

HashiCorp 1.2k Jun 25, 2022
Golang: unify nil and empty slices and maps

unifynil, unify nil and empty slices and maps in Golang Empty slices and maps can be nil or not nil in Go. It may become a nightmare in tests and JSON

Boris Nagaev 0 Jan 16, 2022
memresolver is an in-memory golang resolver that allows to override current golang Lookup func literals

mem-resolver memresolver is an in-memory golang resolver that allows to override current golang Lookup func literals How to use it Create your custom

Antonio Ojea 4 Jun 23, 2022