美文网首页我爱编程
深拷贝和常见一些坑

深拷贝和常见一些坑

作者: 坤_7a1e | 来源:发表于2018-06-07 15:28 被阅读0次

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

    代码示例1:

    package main

    import (

        "fmt"

    )

    type test struct {

        a  int

        b  []int

        c  map[string]int

    }

    func main() {

        //需要给成员c分配内存,不如会抛出异常: panic: assignment to entry in nil map

        //Slice 和 Map 的 nil 值,初始值为 nil 的 Slice 是可以进行“添加”操作的,但是对于 Map 的“添加”操作会导致运行时恐慌。( ﹁ ﹁ ) 恐慌。

        t := &test{c:make(map[string]int, 1)}

        t.a = 1

        t.b = append(t.b, 2)

        t.c["good"] = 3

        t.c["hello"] = 4

        t.c["nice"] = 5

        f := *t

        fmt.Println("before change")

        fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)

        fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)

        fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)

        f.a = 6

        f.b = append(f.b, 7)

        f.c["good"] = 8

        f.c["hello"] = 9

        f.c["nice"] = 10

        fmt.Println()

        fmt.Println("after change")

        fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)

        fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)

        fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)

    }

    运行结果:

    before change

    t.a 1, f.a 1

    t.b [2], f.b [2]

    t.c map[good:3 hello:4 nice:5], f.c map[good:3 hello:4 nice:5]

    after change

    t.a 1, f.a 6

    t.b [2], f.b [2 7]

    t.c map[good:8 hello:9 nice:10], f.c map[good:8 hello:9 nice:10]

    你会发现,将变量t赋值给变量f时候,f中的成员a和成员b 都获得了的拷贝,后续对f中成员a和b的改变,并不会影响t中成员a和b的改变,但是f中成员c获得拷贝是地址的拷贝,后续对f中成员c的改变,会影响t中成员c的改变,如何完整地获得变量t的拷贝,并且操作拷贝的那份数据并不会影响原始数据,查看下面示例2

    代码示例2:

    package main

    import (

        "fmt"

    )

    type test struct {

        a  int

        b  []int

        c  map[string]int

    }

    func deepCopy(dst, src *test)  {

        dst.a = src.a

        dst.c = make(map[string]int, 1)

        for key, val := range src.c {

        dst.c[key] = val

        }

    }

    func main() {

        //需要给成员c分配内存,不如会抛出异常: panic: assignment to entry in nil map

        //

        t := &test{c:make(map[string]int, 1)}

        t.a = 1

        t.b = append(t.b, 2)

        t.c["good"] = 3

        t.c["hello"] = 4

        t.c["nice"] = 5

        f :=*t

        deepCopy(&f, t)

        fmt.Println("before change")

        fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)

         fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)

        fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)

        f.a = 6

        f.b = append(f.b, 7)

        f.c["good"] = 8

        f.c["hello"] = 9

        f.c["nice"] = 10

        fmt.Println()

        fmt.Println("after change")

        fmt.Printf("t.a %v, f.a %v \n", t.a, f.a)

        fmt.Printf("t.b %v, f.b %v \n", t.b, f.b)

        fmt.Printf("t.c %v, f.c %v \n", t.c, f.c)

    }

    运行结果:

    before change

    t.a 1, f.a 1

    t.b [2], f.b [2]

    t.c map[nice:5 good:3 hello:4], f.c map[hello:4 nice:5 good:3]

    after change

    t.a 1, f.a 6

    t.b [2], f.b [2 7]

    t.c map[good:3 hello:4 nice:5], f.c map[hello:9 nice:10 good:8]

    除非特别指定,否则无法使用 nil 对变量赋值

    nil 可以用作 interface、function、pointer、map、slice 和 channel 的“空值”。但是如果不特别指定的话,Go 语言不能识别类型,所以会报错。

    错误信息:

    package main

    func main() {

        var x = nil//error

        _ = x

    }

    错误信息:

        useof untyped nil

    修正代码:

    package main

    func main() {

         var x interface{} = nil

        _ = x

    }

    Map 定长

    创建 Map 的时候可以指定 Map 的长度,但是在运行时是无法使用 cap() 功能重新指定 Map 的大小,Map 是定长的。可以使用len

    字符串无法为 nil

    在 C 语言中是可以char *String=NULL,但是 Go 语言中就无法赋值为 nil。

    参数中的数组

    对于 C 和 C++ 开发者来说,数组就是指针。给函数传递数组就是传递内存地址,对数组的修改就是对原地址数据的修改。但是 Go 语言中,传递的数组不是内存地址,而是原数组的拷贝,所以是无法通过传递数组的方法去修改原地址的数据的。如果需要修改原数组的数据,需要使用数组指针(array pointer)。或者使用slice

    相关文章

      网友评论

        本文标题:深拷贝和常见一些坑

        本文链接:https://www.haomeiwen.com/subject/wljgsftx.html