Go 向函数传递切片该使用值还是指针?

Posted yizdu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go 向函数传递切片该使用值还是指针?相关的知识,希望对你有一定的参考价值。

参考:Go 切片:用法和本质

在Go中,切片的本质是一个结构体,包含一个指向底层数组的指针(prt),长度(len),容量(cap)。所以,切片本身包含一个指针,将切片按值传递给函数,在函数内对其修改,影响将会传递到函数外。因为底层的数组被修改了。
但当对切片进行append()操作,若是元素数量超过原有切片的容量,将会使得切片容量增大,这就是问题所在。扩容后的切片,本质上是产生一个新的底层数组。如果在函数内对切片添加元素导致扩容,会导致元素内的切片指向一个新的数组,但是函数外的切片仍然指向原来旧的数组,则将会导致影响无法传递到函数外。如果希望函数内对切片扩容作用于函数外,就需要以指针形式传递切片。

下面的代码展示了,在change2()内部对切片扩容,导致其指向新的数组,(可以看到切片首个元素地址变了),但是无法影响外部的切片。

package main

import "fmt"

func change1(result []int){
    fmt.Printf("内部1 %p%v len:%d cap:%d\\n",result,result,len(result),cap(result))
    result[0]=9
}
func change2(result []int){
    result=append(result,92)
    fmt.Printf("内部2 %p%v len:%d cap:%d\\n",result,result,len(result),cap(result))
}
func change3(result *[]int){
    *result=append(*result,92)
    fmt.Printf("内部3 %p%v len:%d cap:%d\\n",*result,*result,len(*result),cap(*result))
}

func main(){
    result:=make([]int,1)
    fmt.Printf("外部 %p%v len:%d cap:%d\\n",result,result,len(result),cap(result))
    change1(result)
    fmt.Printf("外部 %p%v len:%d cap:%d\\n",result,result,len(result),cap(result))
    change2(result)
    fmt.Printf("外部 %p%v len:%d cap:%d\\n",result,result,len(result),cap(result))
    change3(&result)
    fmt.Printf("外部 %p%v len:%d cap:%d\\n",result,result,len(result),cap(result))
}

输出

外部 0xc000018100[0] len:1 cap:1
内部1 0xc000018100[0] len:1 cap:1
外部 0xc000018100[9] len:1 cap:1
内部2 0xc000018130[9 92] len:2 cap:2
外部 0xc000018100[9] len:1 cap:1
内部3 0xc000018150[9 92] len:2 cap:2
外部 0xc000018150[9 92] len:2 cap:2

以上是关于Go 向函数传递切片该使用值还是指针?的主要内容,如果未能解决你的问题,请参考以下文章

Golang 函数传参使用切片而不使用数组为什么?

Golang 函数传参使用切片而不使用数组为什么?

golang-101-hacks(12)——切片作为函数参数传递

Go 语言入门三部曲:能看懂 Go 语言

Go切片数组深度解析

Go函数