golang slice 作为参数值传递情况说明

文章通过四个示例探讨了Golang中的slice作为引用类型在函数传递时的行为。尽管Go语言在函数调用时传递的是值,但slice的特殊情况使得函数内对slice的修改会影响到函数外部。示例展示了slice的元素修改、append操作以及使用指针传递slice时的不同效果,解释了为何有时append不会在函数外部生效的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

golang 中引用类型有:slice、map、interface、channel
golang所有类型在函数中都是值传递,这个跟上面golang中有的数据类型为引用类型并不冲突,用下面四个slice实例帮助理解

// 例子 1
func fn(s []int) {
    s[0] = 3
}

func main() {
	slice := []int{1,2}
	fmt.Printf("before fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("before fn slice data:",slice)
	fn(slice)
	fmt.Printf("after fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("after fn slice data:",slice)
}

// 输出结果
// before fn slice len:2, cap:2, add:0xc000132b00before fn slice data: [1 2]
// after fn slice len:2, cap:2, add:0xc000132b00after fn slice data: [3 2]

说明: main 函数中slice[0]说明 fn 函数里面的修改,也改变函数外的值,这跟slice为引用类型的缘故

// 例子 2
func fn(s []int) {
    s[0] = 3
    s = append(s, 4)
    fmt.Printf("fn in slice len:%d, cap:%d, add:%p", len(s), cap(s), s)
    fmt.Println("fn in slice data:", s)
}

func main() {
	slice := []int{1,2}
	fmt.Printf("before fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("before fn slice data:",slice)
	fn(slice)
	fmt.Printf("after fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("after fn slice data:",slice)
}

// 输出结果
// before fn slice len:2, cap:2, add:0xc000026ba0before fn slice data: [1 2]
// fn in slice len:3, cap:4, add:0xc0000244c0fn in slice data: [3 2 4]
// after fn slice len:2, cap:2, add:0xc000026ba0after fn slice data: [3 2]

说明:slice[0] 被修改原因见例1,fn中append的值没有带出来,这里是slice原始分配的空间为2,append导致空间不足,分配新地址,fn外地址不变,导致append的值函数外获取不到??那就分配足够的空间见例3

// 例子 3
func fn(s []int) {
    s[0] = 3
    s = append(s, 4)
    fmt.Printf("fn in slice len:%d, cap:%d, add:%p", len(s), cap(s), s)
    fmt.Println("fn in slice data:", s)
}

func main() {
	slice := make([]int, 0, 4)
	// slice = []int{1,2} // 直接赋值会修改slice的地址
	slice = append(slice,1,2)
	fmt.Printf("before fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("before fn slice data:",slice)
	fn(slice)
	fmt.Printf("after fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("after fn slice data:",slice)
}

// 输出结果
// before fn slice len:2, cap:2, add:0xc000026ba0before fn slice data: [1 2]
// fn in slice len:3, cap:4, add:0xc0000244c0fn in slice data: [3 2 4]
// after fn slice len:2, cap:2, add:0xc000026ba0after fn slice data: [3 2]

说明:slice 分配了足够的空间发现,fn内部append依旧没有生效,观察地址发现fn内部的地址和函数外的地址不一致,因为fn方法参数为切片,而不是切片数组,slice 底层结构为len、cap和指向存储位置的地址,slice 在函数间传递,指向存储位置的地址的指针是一致,但是不同函数的slice不是同一个对下个,对应的len、cap是不一致的

// 例子 4
func fn(s *[]int) {
    (*s)[0] = 3
    *s = append(*s, 4)
}

func main() {
	slice := make([]int, 0, 4)
	// slice = []int{1,2} // 直接赋值会修改slice的地址
	slice = append(slice,1,2)
	fmt.Printf("before fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("before fn slice data:",slice)
	fn(&slice)
	fmt.Printf("after fn slice len:%d, cap:%d, add:%p", len(slice), cap(slice), slice)
	fmt.Println("after fn slice data:",slice)
}

// 输出结果
// before fn slice len:2, cap:2, add:0xc000026b80before fn slice data: [1 2]
// after fn slice len:3, cap:4, add:0xc0000244a0after fn slice data: [3 2 4]

说明:函数间的参数传递改为指针,保证函数内外完全是同一个值,故函数内的修改和append函数外都能获取到

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值