我爱编程

深拷贝和常见一些坑

2018-06-07  本文已影响0人  坤_7a1e

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

上一篇下一篇

猜你喜欢

热点阅读