请教一个 Go 的小白问题

2022-01-12 15:19:46 +08:00
 BryantBa

请教一个 Go 的小白问题

( A ) func DoSomething(a *A) {
        b = a
    }

( B ) func DoSomething(a A) {
        b = &a
    }
   

这两个函数调用的区别具体是什么呢

3451 次点击
所在节点    Go 编程语言
25 条回复
xidaduo
2022-01-12 15:32:37 +08:00
A:引用传递
B:值传递
wunonglin
2022-01-12 15:47:03 +08:00
A:传进来的是那个结构体的内存地址(吧?)
B:通俗来说传入的 a 是 new 了一个一个零值的结构体,然后在把你传的结构赋值上去。
hejw19970413
2022-01-12 16:23:34 +08:00
例如 a 现在的地址为 0x0000000001 值为 1
( A ) 函数中的 a 地址是 0x0000000002 但是 a 的值是 0x0000000001
( B ) 函数中的 a 地址是 0x0000000003 但是 a 的值是 1
Arrowing
2022-01-12 16:53:04 +08:00
*A 是 A 的指针类型
labulaka521
2022-01-12 17:01:30 +08:00
在函数里面修改 b 的值 然后在此函数外面看看 a 的值是否也被改了
milk97
2022-01-12 17:30:34 +08:00
(A) 是 point receiver, https://go.dev/tour/methods/4

如果对 b 做修改,外面 a 指向的值也会变。

( B )这样写意义不大。`b = &a` 中的 a 已经是调用时参数 a 的一个 copy ,再取它的指针没什么意义,因为修改了 b 不是影响到外面的 a 。
qq8331199
2022-01-12 18:23:43 +08:00
@xidaduo 理论上说 go 是没用引用传递的,只有指针传递,指针传递和引用传递是有区别的
DeWjjj
2022-01-12 22:38:40 +08:00
...
一个传进来的东西是指针类型,一个是传值进来取地址然后给 b 。
这差异够大了吧,一个是标识符取地址,一个是指针本身。
&a = 0x02 &c =0x01 c = 1 *a = 1 a=0x01.
1.b = 0x01 = &c
2.b = &a = 0x02
DeWjjj
2022-01-12 22:52:30 +08:00
建议点说就是第一种你改*b 他能影响到外面。
第二种你只能改 b 他影响不到外面。
想要不改数据对外传递处理信息用第二种,想要处理信息顺手改外面传指针进去。
lvdb
2022-01-12 23:25:03 +08:00
要明白这个问题,先要了解引用数据类型,是怎么在内存中存储的。一个 T 类型的对象 t ,实际上需要开辟两种不同的内存空间来存储,t 在栈内存中,而对应的值是在堆内存中。*T 是指向堆内存地址的指针;而&t ,则是栈内存中 t 的地址。
voidmnwzp
2022-01-12 23:39:35 +08:00
c 语言没学过?
chenall
2022-01-13 04:08:58 +08:00
A 这个原始值后续可能会改变,需要同步变化时用。
后续 b=a

B 干净调用,b 是 a 的副本,后续 a 和 b 没有交集。
xsen
2022-01-13 07:00:20 +08:00
A:指针传递,可修改其值
B:值传递,不可修改

对于 go 来说,若你想修改某个参数的值,就需要拿到其指针
xsen
2022-01-13 07:01:13 +08:00
与 c/c++中指针与值概念是一样的,只是用起来没有心理负担
darknoll
2022-01-13 09:45:03 +08:00
go 里面没有引用传参,都是值传递
sozengtao
2022-01-13 11:34:05 +08:00
@darknoll 是的 。老哥说的对 。指针地址也是值 。仅此而已
NeoZephyr
2022-01-13 14:00:53 +08:00
B 属于脱裤子放屁了
meiyoumingzi6
2022-01-13 14:23:42 +08:00
0. 先解释 Golang 的值传递, 注意任何情况下都是值传递, 但是这个值可能是一个地址, 举个例子, 某东有卖螃蟹的, 但是很多是卖的螃蟹券, 我买了螃蟹券, 然后送了人, 那是不是可以说买了螃蟹送礼, 可以, 不过最终需要那个人自提而已
1. 有没有办法证明 Golang 是值传递,
```golang
package main

import "fmt"
type demo struct{}

func test(arg interface{}) {
fmt.Printf("in func test %p\n", &arg)
}



func main() {
d := demo{}
fmt.Printf("out of test %p\n", &d)
test(d)

fmt.Printf("out of test %p\n", &d)
test(&d)

s := []int{1,2,}
fmt.Printf("out of test %p\n", s)
test(s)

m := map[string]int{"1":1}
fmt.Printf("out of test %p\n", m)
test(m)
}

/*
out of test 0x116ce80
in func test 0xc000010230
out of test 0x116ce80
in func test 0xc000010240
out of test 0xc0000160c0
in func test 0xc000010250
out of test 0xc000074180
in func test 0xc000010260
*/
```
2. slice/map 是引用类型, 害, 你就把他当个螃蟹券
3. 题中两个区别
i). 开销不同, a 中值需要赋值一次地址, 开销很小, b 中需要复制一次结构体
ii). 虽然看起来效果一样, 但是 b 中的 a 跟已经跟外面的 a 不是一个东西了, 因为有一次拷贝, 完完全全就是两个东西
dany813
2022-01-13 14:31:21 +08:00
学习了
ixiaofeng
2022-01-13 14:43:25 +08:00
目测这个问题是在看完 the way to go 以后发现的吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/827825

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX