go中数组和Slice作为函数传参时产生的陷阱

本文探讨了Go语言中数组和切片作为函数参数时可能出现的问题。在Go中,数组是值类型,传参时会复制整个数组,导致无法直接修改原数组。而切片虽然可以修改底层数组,但当长度改变或扩容时,底层数组也会变化,影响不到原切片。解决方案包括使用指针或返回新切片。文章详细分析了这些陷阱,并提供了相应的解决策略。
摘要由CSDN通过智能技术生成

起因: 今天在用回溯做leetcode题的时候,用切片作为函数的传参。结果输出的结果和我预想的不符,于是乎想研究一下Slice里面作为函数传参的时候是怎样的。文章主要分为两部分:

  • 使用数组作为传参会产生的陷阱
  • 使用Slice作为传参会产生的陷阱

一、使用数组作为传参会产生的陷阱

首先先看下面代码段:

func foo(a [2]int) {
	a[0] = 10
}

func main() {
	a := [2]int{1, 2}
	foo(a)
	fmt.Println(a)
}

输出的结果竟然是[1,2]数组a并没发生改变

原因:

  • 在go语言中,数组是一个值类型。并且不同长度的数组属于不同的类型。例如[3]int和[10]int属于不同的类型

  • 当值类型作为参数传递时,参数是该值的一个拷贝,因此更改拷贝值并不会更改原值。

解决方案:

1、使用数组指针进行传值

func foo(a *[2]int) {
	(*a)[0] = 10
}

func main() {
	a := [2]int{1, 2}
	foo(&a)
	fmt.Println(a)
}

2、使用切片进行传值

func foo(a []int) {
	a[0] = 10
}

func main() {
	a := []int{1, 2}
	foo(a)
	fmt.Println(a)
}

重点介绍一下为什么使用切片传参就可以:

1、切片是由三个值构成的:

  • *ptr:指向底层数组的指针

  • len:确定切片的长度

  • cap:确定切片的容量

2、当切片作为传参的时候,相当于重新拷贝了一个新的切片,新切片拷贝的原切片的三个值。所以当我们对新切片的值进行修改时候,相当于修改了底层数组中的值,因此会影响到原切片

二、使用Slice作为传参会产生的陷阱

首先先看下面代码:

func foo(a []int) {
	a = append(a, 1, 2, 3, 4)
	a[0] = 10
}

func main() {
	a := []int{1, 2}
	foo(a)
	fmt.Println(a)
}

输出的结果仍然是[1,2]数组a并没发生改变

原因:

  • 传参时虽然拷贝的新的切片,但是因为新切片的长度发生了改变。导致原切片的长度不会发生改变(长度不同的切片对应的类型也不同
  • 其次,新拷贝的切片长度不足以放置4个元素,因此会发生扩容(会产生新的空间)。扩容之后的底层数组就不是原来的底层数组了,所以修改新切片的值不会影响到原切片

解决方案:

1、切片也使用指针方式传递参数

func foo(a *[]int) {
	*a = append(*a, 1, 2, 3, 4)
	(*a)[0] = 10
}

func main() {
	a := []int{1, 2}
	foo(&a)
	fmt.Println(a)
}

2、函数设置切片为返回值

func foo(a []int) []int {
	a = append(a, 1, 2, 3, 4)
	a[0] = 10
	return a
}

func main() {
	a := []int{1, 2}
	a = foo(a)
	fmt.Println(a)
}

3、函数内创建一个零时切片再传递到函数外

result := [][]int{}
func foo(a []int){
	a = append(a, 1, 2, 3, 4)
	a[0] = 10
    temp := make([]int, len(a))
    copy(temp, a)
    result = append(result,temp)
}

func main() {
	a := []int{1, 2}
	foo(a)
	fmt.Println(result[0])
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值