关于切片的实验
1 切片取地址的方法
func main() {
a := []int{1,2,3,4,5}
fmt.Printf("%p\n",&a) //0xc000114060
fmt.Printf("%p\n",a) //0xc00013e060
fmt.Printf("%p\n",&a[0]) //0xc00013e060
}
会发现,a和&a[0]取的是同一个地址,可知直接取a打印的就是切片的第一个元素的内存地址。那第三行打印的是什么呢
打印出所有的地址观察一下
func main() {
a := []int{1,2,3,4,5}
fmt.Printf("%p\n",&a) //0xc000096060
fmt.Printf("%p\n",a) //0xc0000c0060
ptr := &a
fmt.Printf("%p\n",ptr) //0xc000096060
fmt.Printf("%p %p %p %p %p\n",&a[0],&a[1],&a[2],&a[3],&a[4]) //0xc0000c0060 0xc0000c0068 0xc0000c0070 0xc0000c0078 0xc0000c0080
}
可以发现,第三行和第六行打印结果一致,因此可知,当切片使用&时,打印的是切片地址的地址
2 切片的复制操作
func main() {
aa := []int{1,2,3}
a := aa
fmt.Println("a=",a) //a= [1 2 3]
aa = append(aa,4)
fmt.Println("a=",a) //a= [1 2 3]
}
操作a是否会影响aa
func main() {
aa := []int{1,2,3}
a := make([]int,4,8)
a = aa
fmt.Println("a=",a) // a= [1 2 3]
a[1] = 10
fmt.Println("aa=",aa) // aa= [1 10 3]
}
这里看出,当a := aa
,a指向的和aa是同一个,此时改变a的值会影响aa。
修改aa同理
func main() {
aa := []int{1,2,3}
a := aa
fmt.Println("a=",a) // a= [1 2 3]
aa[1] = 10
fmt.Println("a=",a) // a= [1 10 3]
}
3 append操作
func main() {
aa := []int{1,2,3}
a := aa
fmt.Println("a=",a)
aa = append(aa,10) //a = [1 2 3]
fmt.Println("a=",a) //a = [1 2 3]
fmt.Println("aa=",aa) //aa = [1 2 3 10]
}
由于append后,aa的地址发生了改变,此时aa和a指向的已经不是同一块地址,因此aa的改变不会影响a,如下所示
func main() {
aa := []int{1,2,3}
a := aa
fmt.Println("a=",a)
aa = append(aa,10)
fmt.Println("a=",a)
fmt.Println("aa=",aa)
aa[1] = 99
fmt.Println("aa=",aa) //a=[1 99 3 10]
fmt.Println("a=",a) // a = [1 2 3]
}
数组和切片的区别
func main() {
//变量的赋值
var a =10 //定义变量a
b := a //将a的值赋值给b
b = 101 //修改b的值,此时不会影响a
fmt.Printf("a的值是%v,a的内存地址是%p\n",a,&a) //a的值是10,a的内存地址是0xc000128058
fmt.Printf("b的值是%v,b的内存地址是%p\n",b,&b) //b的值是101,b的内存地址是0xc000128070
//数组的赋值
var c =[3]int{1,2,3} //定义一个长度为3的int类型的数组
d := c //将数组c赋值给d
dS := c[1:3]
d[1] = 100 //修改数组d中索引为1的值为100
fmt.Printf("dS的值是%v,dS的内存地址是%p\n",dS,dS) //c的值是[1 2 3],c的内存地址是0xc00012c078
fmt.Printf("c[1]的值是%v,c[1]的内存地址是%p\n",c[1],&c[1]) //c的值是[1 2 3],c的内存地址是0xc00012c078
fmt.Printf("c的值是%v,c的内存地址是%p\n",c,&c) //c的值是[1 2 3],c的内存地址是0xc00012c078
fmt.Printf("d的值是%v,d的内存地址是%p\n",d,&d) //d的值是[1 100 3],d的内存地址是0xc00012c090
//切片赋值
var e = []int{7,8,9}
f := e
f[1] = 100
fmt.Printf("e的值是%v,e的内存地址是%p\n",e,e) //e的值是[7 100 9],e的内存地址是0xc000114060
fmt.Printf("f的值是%v,f的内存地址是%p\n",f,f) //f的值是[7 100 9],f的内存地址是0xc000114078
}
发现,数组赋值d := c时 ,d相当于重新开了一块内存空间,d的改变不会影响c
然而当 dS := c[1:3]时,dS是一个切片,它和数组指向的是同一个地址
一道面试题
type student struct {
Name string `json:"name"`
Num int `json:"num"`
Classes []int `json:"classes"`
}
func main() {
strA := `{"name":"Tom","num":"123","classes":[1,2,3]}`
aa := &student{}
err := json.Unmarshal([]byte(strA),&aa)
if err != nil{
fmt.Println(err)
}
a := aa.Classes
fmt.Println(a) // a = [1 2 3]
strB := `{"name":"Tom","num":"123","classes":[4,5,6,7,8,9]}`
err = json.Unmarshal([]byte(strB),&aa)
if err != nil{
fmt.Println(err)
}
fmt.Println(a) // a = [4 5 6]
}
这里的疑问就是,a在这里为什么当aa被重新赋值以后,a的值也发生了变化,而且虽然发生了变化,却又没有完全和aa.Classes一致。
取地址看看
func main() {
strA := `{"name":"Tom","num":123,"classes":[1,2,3]}`
aa := &student{}
err := json.Unmarshal([]byte(strA),&aa)
if err != nil{
fmt.Println(err)
}
fmt.Println(aa)
a := aa.Classes
fmt.Printf("取aa的地址,aa=%p\n",aa.Classes) //取aa的地址,aa=0xc0000141c0
fmt.Printf("取a的地址,a=%p\n",a) //取a的地址,a=0xc0000141c0
strB := `{"name":"Tom","num":123,"classes":[4,5,6,7,8,9]}`
err = json.Unmarshal([]byte(strB),&aa)
if err != nil{
fmt.Println(err)
}
fmt.Printf("取aa的地址,aa=%p\n",aa.Classes) //取aa的地址,aa=0xc00000c3f0
fmt.Printf("取a的地址,a=%p\n",a) //取a的地址,a=0xc0000141c0
}
感觉很好的文章:
go值传递和地址传递
append原理
slice讲解