Go面试题关于 array 和 slice 一个问题

Posted 小生凡一

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go面试题关于 array 和 slice 一个问题相关的知识,希望对你有一定的参考价值。

文章目录

写在前面

最近有同学问我这个问题啊,以下两个函数输出了什么?

func arrayTest() 
	a := [3]int1, 2, 3
	for k, v := range a 
		if k == 0 
			a[0], a[1] = 100, 200
		
		a[k] = 100 + v
	
	fmt.Println(a)

func sliceTest() 
	a := []int1, 2, 3
	for k, v := range a 
		if k == 0 
			a[0], a[1] = 100, 200
		
		a[k] = 100 + v
	
	fmt.Println(a)

先给结论

  • 数组:[101,102,103]
  • 切片:[101,300,103]

题解

众所周知,Go里面都是值传递,就算是引用类型也是传地址。

我们先了解一下一些数据结构

队列:先进先出
栈:先进后出,在程序调用的时候从栈空间去分配
堆:在程序调用的时候从系统的内存区分配

值类型: 变量直接存储值,内容通常在栈中分配
引用类型: 变量存储的是一个地址,这个地址存储最终的值,内容通常在堆上分配,通过GC回收

那么Go的值传递和引用类型又有哪些?

值类型:基本数据类型intfloatboolstring数组struct
引用类型:指针slicemapchan 等都是引用类型

知道数组是值传递,切片是引用我们就清楚了。

数组只是传递值,相当于深拷贝,无论怎么改变都并不影响原值,而切片是传递地址,改变就会跟着改变

看看这个例子

var x[4]int = [4]int1,2,3,4
var y[4]int = x
fmt.Println(x,y)
y[0]=123
fmt.Println(x,y) 

结果

[1 2 3 4] [1 2 3 4]
[1 2 3 4] [123 2 3 4]

我们可以看到这个数组的改变并不影响原来的数组,那么当我们将这个数组变成切片的时候。

var x[]int = []int1,2,3,4
var y[]int = x
fmt.Println(x,y)
y[0]=123
fmt.Println(x,y) 

结果

[1 2 3 4] [1 2 3 4]
[123 2 3 4] [123 2 3 4]

当我们改变切片的时候,是都变了。

回到这道题上

那么我们知道 数组是值传递,切片是引用传递

func arrayTest() 
	a := [3]int1, 2, 3 	// 数组
	for k, v := range a  
		if k == 0 
			a[0], a[1] = 100, 200 // 改变了
		
		a[k] = 100 + v // 之后又改变了
	
	fmt.Println(a)

所以上面的数组就可以理解为是临时改变了,但是原地址上面的还是原来的值

我们 debug 一下就更清楚了

  • 初始状态

  • 第一次改变


我们发现原来数组a的前两位已经发生了改变

  • 第二次改变

  • 第三次改变


其实我们把 k,v 打印出来就明显很多了,k v从始至终都没有改变过

那么换成切片是什么样子呢?

func sliceTest() 
	a := []int1, 2, 3
	for k, v := range a 
		if k == 0 
			a[0], a[1] = 100, 200
		
		a[k] = 100 + v
	
	fmt.Println(a)

同样debug一下,就很清楚了

注意第一次循环的话,这个v的值是1!!因为已经定下来了


切片的值也已经变了,但是此时v是1!所以这个a[0]=100+1 。 而当下一个之后v就变成200了!!
所以这个300就是这样来的!

所以这里要考察的是go的值传递和引用类型的区别。

参考链接

array与slice的传递方式

以上是关于Go面试题关于 array 和 slice 一个问题的主要内容,如果未能解决你的问题,请参考以下文章

见微知著 带你透过内存看 Slice 和 Array的异同

[Go] Go面试题

[Go] Go面试题

[Go] Go面试题

详解go语言的array和slice

go内建函数(记录)