浅谈Go与习题(四十)

100 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 30 天,点击查看活动详情

今天来学习下Go常见的习题问题(三十九),也是面试中可能会遇到的,让我们来一起学习吧~

关于切片的选择题

昨天看到了一个关于切片的选择题,今天来分享下我对这道题的理解,首先来看下题目的样子,原题是给了4个选项,我们就直接判断输出结果即可

观察下列代码,判断输出结果是什么?为什么?

func change(s []int){
    s = append(s,0)
    for i := range s{
        s[i]++
    }
}
func main(){
    s1 := []int{1,2}
    s2 := s1
    s2 = append(s2,3)
    change(s1)
    change(s2)
    fmt.Println(s1,s2)
}

参考答案:[1,2][2,3,4], 首先对于s1传入到函数change中去,是通过值拷贝传入,因为在go语言中只存在值拷贝的说法,但是由于切片的底层结构是有指针数字、长度、容量三个部分组成,那么存在一个指针成员变量,所以相当于“引用传递”,由于s1初始化的时候,长度和容量都为2,所以在函数change里面进行append操作,会导致长度大于容量,所以会进行扩容操作,这里由于不大于256所以会进行2倍的扩容(扩容规则如下图所示,cap是指新增的容量大小),那么扩容后的数组就不在是原来的数组,会重新make个新的匿名切片,将原数组的值进行拷贝,所以在change函数中操作的结果不会影响main函数中的s1的值

image.png

其次,对于s2来讲由于在传入change函数之前,就已经发生了扩容,此时的s2是指向了长度为3,容量为4的新切片,所以在传入change函数之后,对其进行的append操作,就不会发生扩容,但是此时你会发现,最后的输出结果只有3个数,这也是我一开始不理解的地方,最后我发现由于函数之间是值拷贝,所以除了指针成员变量是引用传递,len和cap是通过值拷贝,也就是说在change函数中改变len和cap的值,是不会改变main函数中的值,他们只是一个拷贝,所以s2的长度在main函数中是3,在change函数中是4,实际上两者都是指向同一个切片,只是长度不一样导致最后输出结果不一样,可以通过反射来修改长度reflect.ValueOf(&s).Elem().SetLen(3)

最后再看一道题,答案放在最后,思考之后,再对答案!!!

func main(){
        slice := make([]int, 2, 3)
	for i := 0; i < len(slice); i++ {
		slice[i] = i
	}
	ret := change(slice)
	ret[1] = 111
	fmt.Println(slice, ret)
 }
func change(s []int) []int {
	s[0] = 10
	s = append(s, 3)
	s = append(s, 4)
	s[1] = 100
	return s
}







总结

今天浅谈了Go的习题(四十),上述第二题答案[10,1] [10 111 3 4],接下来会继续分享其他的习题的相关知识,对于一个刚入门的我来说,还有许多地方需要学习,有错误的地方欢迎大家指出,共同进步!!