go 面试切片的问题

关于切片的实验

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讲解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值