go 我就不用指针不行?

2022-03-25 10:46:33 +08:00
 frank1256

rt ,

搜索引擎告诉我的都是,要改变属性的话就要传指针。是因为如果用值传递,会进行复制一份。这我能理解。

如果不需要改属性就使用值传递,但是不也是复制了一份吗???只不过我没修改属性罢了。

那综上改属性和不改属性都会复制。那什么时候应该用值传递?值传递的所谓的复制一份,危害性很大?那为什么 go 要设计出值传递?

还有人说无脑用指针就行?平时的 crud 里,除了查询出结果的时候,做的赋值动作。需要指针,其他函数之间的流转基本都不会去修改属性的。我用值传递不行吗。

求大佬解答

5436 次点击
所在节点    Go 编程语言
28 条回复
cmdOptionKana
2022-03-25 10:52:38 +08:00
你以前用什么语言,没有值传递、引用传递的区别吗?
mainjzb
2022-03-25 10:53:02 +08:00
指针很小,复制的代价很小很小。
值复制不依赖 gc ,可以减轻 gc 压力。只读的情况下通常复制值给程序带来的压力更小。所以通常建议读取的时候用值复制。
你说的很乱,没太看懂
CokeMine
2022-03-25 10:54:15 +08:00
深拷贝损失性能
你可以去写 JavaScript (
frank1256
2022-03-25 10:57:21 +08:00
@mainjzb 了解了,描述不太清楚
pultako
2022-03-25 11:03:12 +08:00
go 里面参数传递只有值拷贝这一种方式, 你说的"值传递"和"传指针"两者的区别仅仅在于是拷贝的是一整个结构体还是指针
无脑用指针也是不可取的, 因为内存逃逸的原因, GC 压力会很大.
一般来说在 crud 里, 查询结果返回使用指针传递, 请求的参数结构体 /中间变量直接使用结构体.
YUyu101
2022-03-25 11:03:24 +08:00
不是大块数据结构,内存复制快啊,以前写 java 好像只有 integer 这些基础类型会拆箱成值传递,其他都是对象分配在堆上传引用,go 自己怎么传自由一点。
chengyiqun
2022-03-25 11:03:45 +08:00
值传递又不是 go 独有的, 很多语言都有值传递, 而且占据大多数, 像 c 和 java.
而且 java 不存在引用传递一说, 全都是值传递. 只是传递对象的时候, 传递的是对象的指针, 所以仿佛看上去像引用传递而已.
值传递的目的应该是为了减少变量的作用范围, 因为要用到引用传递的地方通常是没有值传递多的.
很多时候, 一个函数输入数据, 输出数据, 不需要改变原输入数据.
chengyiqun
2022-03-25 11:06:12 +08:00
而且正如楼上说的, 值传递复制的变量是在栈上的, 出了方法就自动销毁, 回收代价很小, 分配很快.
Mexion
2022-03-25 11:13:49 +08:00
不改属性确实直接可以用值,但是如果结构数据很大,copy 性能较低
txx
2022-03-25 11:21:27 +08:00
之前一直以为 Go 的 值传递也和 Swift 一样是 Copy-on-Write ... 😂
littlewing
2022-03-25 11:26:37 +08:00
不改变属性应该用

const T&

或者 非 mut borrowing

手动狗头.jpg
lxz6597863
2022-03-25 12:10:30 +08:00
粗暴点来讲:
对象生命周期很长的,用指针来传
对象结构数据很大的,用指针来传

其他不改动属性的情况,无脑用值
fgwmlhdkkkw
2022-03-25 12:16:45 +08:00
所有语言传参都是传值!!!!!!但值的意义由你来定。
lysS
2022-03-25 12:19:46 +08:00
go 的指针是安全的,不想 C 的
wenning
2022-03-25 12:30:53 +08:00
@lxz6597863 赞同你的意见; 大多数时候无脑用值, 还能避免很多空指针的 panic
yousabuk
2022-03-25 12:48:07 +08:00
非超级大数据量值传递没有危害,甚至都不会影响电脑性能。

内存拷贝的压力很小的,试了下,采集 4 台射频信号,100M IQ 采样速率(每台每秒 100 * 2 * 2 = 400Mbyte )改用内存拷贝的方式再进行数据运算处理抽值绘制波形图,也够的,不影响电脑使用。当然,还是会选择用指针的方式来操作数据。
XTTX
2022-03-25 12:52:36 +08:00
@fgwmlhdkkkw #13 啊?!!!!!! 你是怎么敢打那么多感叹号的
ligiggy
2022-03-25 13:11:29 +08:00
@XTTX !!!!!!!!!!!!!!!!!
GeruzoniAnsasu
2022-03-25 13:16:20 +08:00
如下机制必须使用指针:

type T struct {
Field int
}

func (t *T) SetValue(v int) {
t.Field = v
}

var t T
t.SetValue(1) // 否则 t 的值永远不会改变

如下结构传递值会有问题:
defer func(v T){someChan <-v}(vv) // channel 捕捉不到 v 的最后状态而是当前值

gorm 的 scan 使用了大一 C 语言教科书级别的指针传递:
db.Where("id = ?", 1).Scan(&ModeledValue)




无脑用指针的话:

func (*T) TableName() string {
return "t_"
}

你要写 db.Table((&T{}).TableName()) ,本来可以 db.Table(T{}.TableName())




还有浅拷贝的问题:

type T struct{v:int}
type U struct{t *T}
type N struct {u *U}

t := T{v:1}
u := U{}
n := N{}

n.u = &u
u.t = &t


func foo(n *N) N {
return N{u: &U{t: n.u.t}}// 我想「用 n 的值初始化一个新 N 」
}

newN := foo(&n)
newN.u.t.v = 2
n.u.t.v == 2 //但其实 n.u.t 被改了


ref: https://go.dev/play/p/74Q6bC13xN0
BeautifulSoap
2022-03-25 13:37:03 +08:00
排除需要修改值得情况,大部分人纠结传指针还是传值往往是在纠结对 struct 来说,我到底是该传值还是指针

很多人都会有种误解,认为传 struct 的指针比复制一份值快很多,所以喜欢传 struct 的指针。但实际上并不是的,指针引用的对象是分配到堆上的,在函数内使用指针引用的值都需要取堆去取,并且堆中的内存受 GC 管理会增加 GC 压力。而传值的话复制后的值会直接分配在栈上,栈的速度比堆快,并且函数执行完毕后栈会销毁没有 GC 之类的压力。

所以传值还是传指针,还是要取决于 struct 的大小,如果 struct 本身很大,复制一个 struct 的成本大于用指针直接引用的性能消耗那么可以考虑传指针。

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

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

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

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

© 2021 V2EX