Go语言(Golang)地址引用避坑

1、channel

先看以下代码:

package main

import "fmt"

func main() {
	ch1 := make(chan int, 3)
	ch2 := ch1
	ch1 <- 123
	ch2 <- 456
	fmt.Println(ch1, ch2)     //输出地址是否一样?  TODO:打印结果是?
	fmt.Println(<-ch2, <-ch1) // ch2中的数据是:456; ch1中的数据是123;TODO:打印结果是?
}

输出结果:

Go语言(Golang)地址引用避坑_第1张图片

代码分析:

在以上代码中,新定义的变量ch2:=ch1 ;ch2是地址引用,ch1,ch2地址指向的是同一块数据,ch1、ch2都可以改变数据。

2、slice

看看以下代码:

package main

import "fmt"

func main() {
	s := make([]int, 3)
	s1 := s
	s2 := s
	s[0] = 123
	s1[1] = 456
	s2[2] = 789
	fmt.Println("原始切片:", s)
	fmt.Println("赋值切片:", s1)
	fmt.Println("赋值切片:", s2)
	fmt.Println("切片的长度、容量为:", len(s), cap(s))
	fmt.Printf("追加之前的地址:s:%p ;s1:%p; s2:%p\n",s,s1,s2)
	fmt.Println("====执行append操作====")
	s2 = append(s2, 123)
	fmt.Printf("追加之后的地址:s:%p ;s1:%p; s2:%p\n",s,s1,s2)
	fmt.Println("原始切片s:", s)
	fmt.Println("赋值切片s1:", s1)
	fmt.Println("赋值切片s2:", s2)
}

输出结果:

Go语言(Golang)地址引用避坑_第2张图片

代码分析:起初,s,s1,s2都指向同一块数据。所以任意一个变量修改了该块数据,其他变量查到的都是修改之后的数据。

指向:

s2 = append(s2, 123),会在末尾追加一个元素,由于现有s2的
cap(s)=3, len(s)=3;

在追加数据时,容量已经不够,会开辟新的内存,将现有数据s2拷贝,形成新的s2。当然在容量足够的情况下,不会开辟新的内存空间。

再来看以下代码:(容量大于append的数据数量)

package main

import "fmt"

func main() {
	s := make([]int, 3,6)
	s1 := s
	s2 := s
	s[0] = 123
	s1[1] = 456
	s2[2] = 789
	fmt.Println("原始切片:", s)
	fmt.Println("赋值切片:", s1)
	fmt.Println("赋值切片:", s2)
	fmt.Println("切片的长度、容量为:", len(s), cap(s))
	fmt.Printf("追加之前的地址:s:%p ;s1:%p; s2:%p\n",s,s1,s2)
	fmt.Println("====执行append操作====")
	s2 = append(s2, 123)
	fmt.Printf("追加之后的地址:s:%p ;s1:%p; s2:%p\n",s,s1,s2)
	s[0]=888 // TODO:会修改s1、s2吗
	fmt.Println("原始切片s:", s)
	fmt.Println("赋值切片s1:", s1)
	fmt.Println("赋值切片s2:", s2)
}

输出效果:

Go语言(Golang)地址引用避坑_第3张图片

在以上代码中添加内容:

package main

import "fmt"

func main() {
	s := make([]int, 3,6)
	s1 := s
	s2 := s
	s[0] = 123
	s1[1] = 456
	s2[2] = 789
	fmt.Println("原始切片:", s)
	fmt.Println("赋值切片:", s1)
	fmt.Println("赋值切片:", s2)
	fmt.Println("切片的长度、容量为:", len(s), cap(s))
	fmt.Printf("追加之前的地址:s:%p ;s1:%p; s2:%p\n",s,s1,s2)
	fmt.Println("====执行append操作====")
	s2 = append(s2, 123)
	fmt.Printf("追加之后的地址:s:%p ;s1:%p; s2:%p\n",s,s1,s2)
	s[0]=888 // TODO:会修改s1、s2吗
	fmt.Println("原始切片s:", s)
	fmt.Println("赋值切片s1:", s1)
	fmt.Println("赋值切片s2:", s2)
	fmt.Println("执行以下操作,输出结果又是什么呢?")
	s = append(s, 666)
	fmt.Println("原始切片s:", s)
	fmt.Println("赋值切片s1:", s1)
	fmt.Println("赋值切片s2:", s2)
}

Go语言(Golang)地址引用避坑_第4张图片

特别说明:Go语言为了节省内存空间,对于切片、map、channel、指针等地址引用的变量,会操作同一块地址对应的数据,在操作时也特别留意。

你可能感兴趣的:(Golang)