SoFunction
Updated on 2025-03-05

Golang Copier's introduction to the pitfall

text

github: /jinzhu/copier

becausegolangNo complex structurecloneMethod, so, you need to havecopierSuch a tool library.

It looks very simple, but in actual use, you still need to pay attention to some "pits"!

This article:

Be the auxiliary of the entry, and explore the "pit" as the main point.

I took the slim away after reading it, I didn't have it.

Install

go get /jinzhu/copier

Quick Start

OK, let’s get a quick understanding of itcopier

package main
import (
    "fmt"
    "/jinzhu/copier"
)
type SC struct {
    C uint8
}
type M1 struct {
    A int
    W string
    S *SC
}
func main() {
    var src = M1{12, "Hello", &SC{32}}
    var dst = M1{}
    ("before copy src %+v\tdst %+v\n", src, dst)
    (&dst, src)
    ("after  copy src %+v\tdst %+v\n", src, dst)
}

Output:

before copy src {A:12 W:Hello S:0xc00017f550}   dst {A:0 W: S:<nil>}
after  copy src {A:12 W:Hello S:0xc00017f550}   dst {A:12 W:Hello S:0xc00017f618}

OK, you've got it rightcopier80% of the features. Don’t rush to take the lead, and then record the pit.

The output of this code running is based on the results of the /jinzhu/[email protected] and go1.16.1 darwin/amd64 environment demonstration.

Enter the pit

package main
import (
    "fmt"
    "/davecgh/go-spew/spew"
    "/jinzhu/copier"
)
type SC struct {
    C uint8
}
type Map1 struct {
    M map[string]int32
    A []int32
    C *SC
}
func main() {
    var src = Map1{map[string]int32{"C:": 3, "d": 4}, []int32{9, 8}, &SC{32}}
    var dst1 = Map1{}
    ("before src %+v\t\tdst %+v\n", src, dst1)
    (&dst1, src)
    ["F"] = 5
    ["g"] = 6
    [0] = 7
     = 27
    ("after  src %+v\tdst %+v\n", src, dst1)
}

After the above code is run, it will output:

before src {M:map[C::3 d:4] A:[9 8] C:<*>(0xc00012a1e8){C:32}}          dst {M:<nil> A:<nil> C:<nil>}

befre that line of code is as above ⬆️, what will output after that line?

1. after  src {M:map[C::3 d:4] A:[9 8] C:<*>(0xc00012a1e8){C:27}}  dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
2. after  src {M:map[C::3 d:4] A:[9 8] C:<*>(0xc00012a1e8){C:32}}  dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
3. after  src {M:map[C::3 d:4] A:[7 8] C:<*>(0xc00012a1e8){C:32}}  dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
4. after  src {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a1e8){C:32}}  dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}
5. after  src {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a1e8){C:27}}  dst {M:map[C::3 d:4 F:5 g:6] A:[7 8] C:<*>(0xc00012a348){C:27}}

The answer is: var a = int(759 / 6 / 31.5)

To avoid accidentally reading the answer, please calculate the value obtained by 759 / 6 / 31.5 rounded to be.

Find out the pit again

I see other students using itcopierIt's also like the above-($dst, src), Of course, I am not ruled out! It seems like a small and delicate knife. A simple function call completes its mission.

However, it is actually a multi-function knife, and I haven't even opened it yet-option

The above problem is that after I copy, the change to the value affects the map of another value. At this time, deep copy is needed. Next introducecopierofoption

package main
import (
    "fmt"
    "/davecgh/go-spew/spew"
    "/jinzhu/copier"
)
type SC struct {
    C uint8
}
type Map1 struct {
    M map[string]int32
    A []int32
    C *SC
}
func main() {
    var src = Map1{map[string]int32{"C:": 3, "d": 4}, []int32{9, 8}, &amp;SC{32}}
    var dst1 = Map1{}
    ("before src %+v\t\tdst %+v\n", src, dst1)
    (&amp;dst1, src, {DeepCopy: true})   // here!    ["F"] = 5
    ["g"] = 6
    [0] = 7
     = 27
    ("after  src %+v\tdst %+v\n", src, dst1)
}

OK, after copying, the changes to the new variable will not be passed and the original variable will be changed.

Another pitfall

package main
import (
    "fmt"
    "/davecgh/go-spew/spew"
    "/jinzhu/copier"
)
type ArrTC struct {
    Name [2]string
    C    *ArrTC
}
type ArrT struct {
    A  [3]int32
    S  []int32
    E  []int32
    C  string
    V  string
    M map[string]int32
    AC ArrTC
    s bool
}
func main() {
    var src = ArrT{
        [3]int32{9, 10, 0},
        []int32{12, 0},
        []int32{},
        "",
        "val",
        map[string]int32{"A:": 1, "b": 0},
        ArrTC{},
        true,
    }
    var dst = ArrT{
        [3]int32{1, 2, 3},
        []int32{4, 5, 6, 7},
        []int32{9, 10},
        "char",
        "ha",
        map[string]int32{"C:": 3, "b": 4, ".": 0},
        ArrTC{[2]string{"Y", "Z"}, nil},
        false,
    }
    ("before src %+v\tdst %+v\n", src, dst)
    (&dst, src, {IgnoreEmpty: true, DeepCopy: true})
    ("after  src %+v\tdst %+v\n", src, dst)
    ["b"] = 99
    [1] = 1
    [0] = 2
    ("last  src %+v\tdst %+v\n\n", src, dst)
}

Output:

before src {A:[9 10 0] S:[12 0] E:[] C: V:val M:map[A::1 b:0] AC:{Name:[ ] C:<nil>} s:true}    dst {A:[1 2 3] S:[4 5 6 7] E:[9 10] C:char V:ha M:map[C::3 b:4 .:0] AC:{Name:[Y Z] C:<nil>} s:false}
after  src {A:[9 10 0] S:[12 0] E:[] C: V:val M:map[A::1 b:0] AC:{Name:[ ] C:<nil>} s:true}    dst {A:[9 10 0] S:[12 0 6 7] E:[9 10] C:char V:val M:map[A::1 C::3 b:0 .:0] AC:{Name:[Y Z] C:<nil>} s:true}
last  src {A:[9 10 0] S:[12 1] E:[] C: V:val M:map[A::1 b:99] AC:{Name:[ ] C:<nil>} s:true}    dst {A:[9 10 0] S:[2 0 6 7] E:[9 10] C:char V:val M:map[C::3 b:0 .:0 A::1] AC:{Name:[Y Z] C:<nil>} s:true}

I added the code this timeIgnoreEmpty: true, that is, the empty value is ignored when copying. In other words, it can be used as a value merge.

Then, the variable independence was tested. After copying,srcdstThe two variables have no connection, and any changes to one of the values ​​will not be synchronized to the other.

But, thismergeThe performance may not be what you think.

 = []int32{12, 0}
 = []int32{4, 5, 6, 7}
## What are your expected results after calling copy?  [6/7]6.  = []int32{12, 0}
7.  = []int32{12, 0, 6, 7}
  • Option 6: Well, it turns out that {12, 0} is copied to dst and that is {12, 0}
  • Option 7: This is a slice, you only give me the value of 0 and 1 bits, and copier puts the value of 0 and 1 bitscopyNow,dstThe following 2 and 3 digits value,srcIf you don't give it, then don't care. So it is {12, 0, 6, 7}

I think the performance in this area is controversial. The big guys leave your expected options in the comment section to see if everyone thinks so.

The actual operation result can be found by looking at the above code output.

Conclusion

copierIt was originally a short and concise tool library, but I didn’t want to have a good article. Recently, I suddenly stepped on a pit and opened a special article to share with you my experience of stepping on a pit.

When using external libraries, it is recommended to gogithubCheck out the detailed instructions, orCheck out the interface and instructions it exposed. Or conduct a complete test and fully understand it before using it.

The above is the detailed content of Golang Copier’s introduction to the pitfalls. For more information about Golang Copier’s introduction, please follow my other related articles!