天天看点

go语言深拷贝和浅拷贝案例

%T :使用Go语法输出的值的类型

%v:使用默认格式输出的内置或者自定义类型的值,或者是使用其类型的String()方式输出的自定义值,如果该方法存在的话

%p:以十六进制(基数为16)表示的一个值的地址,前缀为0x,字母使用小写的a-f表示

go语言深拷贝和浅拷贝案例

1、浅复制(1)new()和:=

package main

import "fmt"

type dog struct {
    name string
    age  int
    sex  int
}

func main() {
    dog1 := new(dog)
    dog1.name = "dog1"
    dog1.age = 11
    dog1.sex = -1

    dog2 := dog1

    fmt.Printf("%T %v %p\n", dog1, dog1, dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, dog2)

    dog2.name = "dog2"
    dog2.age = 12
    dog2.sex = 2
    fmt.Printf("%T %v %p\n", dog1, dog1, dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, dog2)
}      
go语言深拷贝和浅拷贝案例

2、浅复制(2)结构名{}和 :=&

package main

import "fmt"

type dog struct {
    name string
    age  int
    sex  int
}

func main() {
    dog1 := dog{
        name: "dog1",
        age:  11,
        sex:  -1,
    }
    dog2 := &dog1

    fmt.Printf("%T %v %p\n", dog1, dog1, &dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, dog2)

    dog2.name = "dog2"
    dog2.age = 12
    dog2.sex = 2
    fmt.Printf("%T %v %p\n", dog1, dog1, &dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, dog2)
}      
go语言深拷贝和浅拷贝案例

3、浅复制(3) 切片

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    slice_test := []int{1, 2, 3, 4, 5}

    fmt.Println(unsafe.Sizeof(slice_test))
    fmt.Printf("main:%#v,%#v,%#v\n\n", slice_test, len(slice_test), cap(slice_test))

    slice_value(slice_test)
    fmt.Printf("after slice_test,main:%#v,%#v,%#v\n\n", slice_test, len(slice_test), cap(slice_test))

    slice_ptr(&slice_test)
    fmt.Printf("after slice_ptr,main:%#v,%#v,%#v\n\n", slice_test, len(slice_test), cap(slice_test))

    fmt.Println(unsafe.Sizeof(slice_test))
}

func slice_value(slice_test []int) {
    slice_test[1] = 100                // 函数里的slice确实有被修改
    slice_test = append(slice_test, 6) // 函数外的不变
    fmt.Printf("slice_value:%#v,%#v,%#v\n\n", slice_test, len(slice_test), cap(slice_test))
}

func slice_ptr(slice_test *[]int) { // 这样才能修改函数外的slice
    (*slice_test)[1] = 10
    *slice_test = append(*slice_test, 7)
    fmt.Printf("slice_ptr:%#v,%#v,%#v\n\n", *slice_test, len(*slice_test), cap(*slice_test))
}      
go语言深拷贝和浅拷贝案例

​​unsafe.sizeof()​​

4、 深复制(1)结构名{}和:=

package main

import "fmt"

type dog struct {
    name string
    age  int
    sex  int
}

func main() {
    dog1 := dog{
        name: "dog1",
        age:  11,
        sex:  -1,
    }
    dog2 := dog1

    fmt.Printf("%T %v %p\n", dog1, dog1, &dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, &dog2)

    dog2.name = "dog2"
    dog2.age = 12
    dog2.sex = 2
    fmt.Printf("%T %v %p\n", dog1, dog1, &dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, &dog2)
}      
go语言深拷贝和浅拷贝案例

5、深复制(2)指针

package main
import "fmt"

type dog struct {
    name string
    age  int
    sex  int
}

func main() {
    dog1 := &dog{
        name: "dog1",
        age:  11,
        sex:  -1,
    }
    dog1Ptr := *dog1
    dog2 :=  &dog1Ptr

    fmt.Printf("%T %v %p\n", dog1, dog1, dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, dog2)

    dog2.name = "dog2"
    dog2.age = 12
    dog2.sex = 2
    fmt.Printf("%T %v %p\n", dog1, dog1, dog1)
    fmt.Printf("%T %v %p\n", dog2, dog2, dog2)
}      
go语言深拷贝和浅拷贝案例

评论区说的没错,以上只能处理没有指针属性的结构体

golang 完全是按值传递,所以正常的赋值都是值拷贝,当然如果类型里面嵌套的有指针,也是指针值的拷贝,此时就会出现两个类型变量的内部有一部分是共享的。

package main

import "fmt"

type dog struct {
    name string
    age  int
    sex  int
    son  *dog
}

func main() {
    dogSon := dog{
        name :"dogSon1",
        age:1,
        sex: 1,
        son:nil,
    }
    dog1 := dog{
        name: "dog1",
        age:  11,
        sex:  -1,
        son:&dogSon,
    }
    dog2 := dog1
    fmt.Printf("Before Change dog2.son's information:\n")
    fmt.Printf("do1.son:%T %v %p\n", dog1.son, dog1.son, &dog1.son)
    fmt.Printf("dog2.son:%T %v %p\n", dog2.son, dog2.son, &dog2.son)

    fmt.Printf("\nAfter Change dog2.son's information:\n")
    dog2.son.name = "dogSon2"
    dog2.son.age = 2
    dog2.son.sex = 2

    fmt.Printf("%T %v %p\n", dogSon, dogSon, &dogSon)
    fmt.Printf("dog1.son:%T %v %p\n", dog1.son, dog1.son, &dog1.son)
    fmt.Printf("dog2.son:%T %v %p\n", dog2.son, dog2.son, &dog2.son)
}      

6、基于序列化和反序列化来实现对象的深度复制

package main

import (
    "bytes"
    "encoding/gob"
    "fmt"
)

type Dog struct {    // 结构体序列化时,需要序列化的字段需要首字母大写。
    Name string
    Age  int
    Sex  int
    Son  *Dog
}

func deepcopy(dst, src interface{}) error{
    var buffer bytes.Buffer    //构造缓冲区
    // 序列化,生成gob编码器并编码
    if err:= gob.NewEncoder(&buffer).Encode(src);err!=nil{
        return err
    }
    // 反序列化,构造gob解码器,解码
    return gob.NewDecoder(bytes.NewBuffer(buffer.Bytes())).Decode(dst)
}

func main() {
    dogSon := Dog{
        Name :"dogSon1",
        Age:1,
        Sex: 1,
        Son:nil,
    }
    dog1 := Dog{
        Name: "dog1",
        Age:  11,
        Sex:  -1,
        Son:&dogSon,
    }
    var dog2 Dog
    err := deepcopy(&dog2, &dog1)
    if err != nil{
        fmt.Println(err)
    }else {
        fmt.Printf("Before Change dog2.Son's information:\n")
        fmt.Printf("do1.Son:%T %v %p\n", dog1.Son, dog1.Son, &dog1.Son)
        fmt.Printf("dog2.Son:%T %v %p\n", dog2.Son, dog2.Son, &dog2.Son)

        fmt.Printf("\nAfter Change dog2.Son's information:\n")
        dog2.Son.Name = "dogSon2"
        dog2.Son.Age = 2
        dog2.Son.Sex = 2

        fmt.Printf("%T %v %p\n", dogSon, dogSon, &dogSon)
        fmt.Printf("dog1.Son:%T %v %p\n", dog1.Son, dog1.Son, &dog1.Son)
        fmt.Printf("dog2.Son:%T %v %p\n", dog2.Son, dog2.Son, &dog2.Son)
    }
}