最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

【天天报资讯】Go的参数是传值还是传引用问题

来源:博客园


【资料图】

什么是传值(值传递)

func main() {i:=10ip:=&ifmt.Printf("原始指针的内存地址是:%p\n",&ip)modify(ip)fmt.Println("int值被修改了,新值为:",i)} func modify(ip *int){ fmt.Printf("函数里接收到的指针的内存地址是:%p\n",&ip) *ip=1 }/*原始指针的内存地址是:0xc42000c028函数里接收到的指针的内存地址是:0xc42000c038int值被修改了,新值为: 1*/

这是一个指针的拷贝,因为存放这两个指针的内存地址是不同的,虽然指针指向的值相同,但是是两个不同的指针。

Go语言是没有引用传递的

因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;

有的是引用类型(指针、map、slice、chan等这些),传递的是指针的副本,指向同一份数据,这样就可以修改原内容数据。

之所以对于引用类型的传递可以修改原内容的数据,这是因为在底层默认使用该引用类型的指针进行传递,但也是使用指针的副本,依旧是值传递。

slice

func main()  { var args =  []int64{1,2,3} fmt.Printf("切片args的地址: %p \n",args) fmt.Printf("切片args第一个元素的地址: %p \n",&args[0]) fmt.Printf("直接对切片args取地址%v \n",&args) modifiedNumber(args) fmt.Println(args)}func modifiedNumber(args []int64)  {    fmt.Printf("形参切片的地址 %p \n",args)    fmt.Printf("形参切片args第一个元素的地址: %p \n",&args[0])    fmt.Printf("直接对形参切片args取地址%v \n",&args)    args[0] = 10}/*切片args的地址: 0xc000016140 切片args第一个元素的地址: 0xc000016140 直接对切片args取地址&[1 2 3] 形参切片的地址 0xc000016140 形参切片args第一个元素的地址: 0xc000016140 直接对形参切片args取地址&[1 2 3] [10 2 3]*/

为什么两个指针一样:

func (p *pp) fmtPointer(value reflect.Value, verb rune) {    var u uintptr    switch value.Kind() {    case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:        u = value.Pointer()    default:        p.badVerb(verb)        return    }...... 省略部分代码// If v"s Kind is Slice, the returned pointer is to the first// element of the slice. If the slice is nil the returned value// is 0.  If the slice is empty but non-nil the return value is non-zero. func (v Value) Pointer() uintptr {    // TODO: deprecate    k := v.kind()    switch k {    case Chan, Map, Ptr, UnsafePointer:        return uintptr(v.pointer())    case Func:        if v.flag&flagMethod != 0 { ....... 省略部分代码//如果是slice类型,返回slice这个结构里的第一个元素的地址。

map

func main()  {    persons:=make(map[string]int)    persons["asong"]=8    addr:=&persons    fmt.Printf("原始map的内存地址是:%p\n",addr)    modifiedAge(persons)    fmt.Println("map值被修改了,新值为:",persons)}func modifiedAge(person map[string]int)  {    fmt.Printf("函数里接收到map的内存地址是:%p\n",&person)    person["asong"]=9}/*原始map的内存地址是:0xc00000e028函数里接收到map的内存地址是:0xc00000e038map值被修改了,新值为: map[asong:9]*/

传递参数时还是使用了指针的副本进行传递,属于值传递。只是指向了同一份数据。

chan

func main()  {    p:=make(chan bool)    fmt.Printf("原始chan的内存地址是:%p\n",&p)    go func(p chan bool){        fmt.Printf("函数里接收到chan的内存地址是:%p\n",&p)        //模拟耗时        time.Sleep(2*time.Second)        p<-true    }(p)    select {    case l := <- p:        fmt.Println(l)    }}/*原始chan的内存地址是:0xc00000e028函数里接收到chan的内存地址是:0xc00000e038tru*/

同理。

关键词: 引用类型 是不同的