rt ,
搜索引擎告诉我的都是,要改变属性的话就要传指针。是因为如果用值传递,会进行复制一份。这我能理解。
如果不需要改属性就使用值传递,但是不也是复制了一份吗???只不过我没修改属性罢了。
那综上改属性和不改属性都会复制。那什么时候应该用值传递?值传递的所谓的复制一份,危害性很大?那为什么 go 要设计出值传递?
还有人说无脑用指针就行?平时的 crud 里,除了查询出结果的时候,做的赋值动作。需要指针,其他函数之间的流转基本都不会去修改属性的。我用值传递不行吗。
求大佬解答
1
cmdOptionKana 2022-03-25 10:52:38 +08:00 9
你以前用什么语言,没有值传递、引用传递的区别吗?
|
2
mainjzb 2022-03-25 10:53:02 +08:00
指针很小,复制的代价很小很小。
值复制不依赖 gc ,可以减轻 gc 压力。只读的情况下通常复制值给程序带来的压力更小。所以通常建议读取的时候用值复制。 你说的很乱,没太看懂 |
3
CokeMine 2022-03-25 10:54:15 +08:00 via Android
深拷贝损失性能
你可以去写 JavaScript ( |
5
pultako 2022-03-25 11:03:12 +08:00 2
go 里面参数传递只有值拷贝这一种方式, 你说的"值传递"和"传指针"两者的区别仅仅在于是拷贝的是一整个结构体还是指针
无脑用指针也是不可取的, 因为内存逃逸的原因, GC 压力会很大. 一般来说在 crud 里, 查询结果返回使用指针传递, 请求的参数结构体 /中间变量直接使用结构体. |
6
YUyu101 2022-03-25 11:03:24 +08:00
不是大块数据结构,内存复制快啊,以前写 java 好像只有 integer 这些基础类型会拆箱成值传递,其他都是对象分配在堆上传引用,go 自己怎么传自由一点。
|
7
chengyiqun 2022-03-25 11:03:45 +08:00
值传递又不是 go 独有的, 很多语言都有值传递, 而且占据大多数, 像 c 和 java.
而且 java 不存在引用传递一说, 全都是值传递. 只是传递对象的时候, 传递的是对象的指针, 所以仿佛看上去像引用传递而已. 值传递的目的应该是为了减少变量的作用范围, 因为要用到引用传递的地方通常是没有值传递多的. 很多时候, 一个函数输入数据, 输出数据, 不需要改变原输入数据. |
8
chengyiqun 2022-03-25 11:06:12 +08:00
而且正如楼上说的, 值传递复制的变量是在栈上的, 出了方法就自动销毁, 回收代价很小, 分配很快.
|
9
Mexion 2022-03-25 11:13:49 +08:00
不改属性确实直接可以用值,但是如果结构数据很大,copy 性能较低
|
10
txx 2022-03-25 11:21:27 +08:00
之前一直以为 Go 的 值传递也和 Swift 一样是 Copy-on-Write ... 😂
|
11
littlewing 2022-03-25 11:26:37 +08:00
不改变属性应该用
const T& 或者 非 mut borrowing 手动狗头.jpg |
12
lxz6597863 2022-03-25 12:10:30 +08:00
粗暴点来讲:
对象生命周期很长的,用指针来传 对象结构数据很大的,用指针来传 其他不改动属性的情况,无脑用值 |
13
fgwmlhdkkkw 2022-03-25 12:16:45 +08:00
所有语言传参都是传值!!!!!!但值的意义由你来定。
|
14
lysS 2022-03-25 12:19:46 +08:00
go 的指针是安全的,不想 C 的
|
15
wenning 2022-03-25 12:30:53 +08:00
@lxz6597863 赞同你的意见; 大多数时候无脑用值, 还能避免很多空指针的 panic
|
16
yousabuk 2022-03-25 12:48:07 +08:00 via iPhone
非超级大数据量值传递没有危害,甚至都不会影响电脑性能。
内存拷贝的压力很小的,试了下,采集 4 台射频信号,100M IQ 采样速率(每台每秒 100 * 2 * 2 = 400Mbyte )改用内存拷贝的方式再进行数据运算处理抽值绘制波形图,也够的,不影响电脑使用。当然,还是会选择用指针的方式来操作数据。 |
17
XTTX 2022-03-25 12:52:36 +08:00 1
@fgwmlhdkkkw #13 啊?!!!!!! 你是怎么敢打那么多感叹号的
|
19
GeruzoniAnsasu 2022-03-25 13:16:20 +08:00 1
如下机制必须使用指针:
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 |
20
BeautifulSoap 2022-03-25 13:37:03 +08:00 2
排除需要修改值得情况,大部分人纠结传指针还是传值往往是在纠结对 struct 来说,我到底是该传值还是指针
很多人都会有种误解,认为传 struct 的指针比复制一份值快很多,所以喜欢传 struct 的指针。但实际上并不是的,指针引用的对象是分配到堆上的,在函数内使用指针引用的值都需要取堆去取,并且堆中的内存受 GC 管理会增加 GC 压力。而传值的话复制后的值会直接分配在栈上,栈的速度比堆快,并且函数执行完毕后栈会销毁没有 GC 之类的压力。 所以传值还是传指针,还是要取决于 struct 的大小,如果 struct 本身很大,复制一个 struct 的成本大于用指针直接引用的性能消耗那么可以考虑传指针。 |
21
duckyrain 2022-03-25 17:36:16 +08:00
优先使用值传递。如果指针传递更优,go 就不会默认用值传递了。两篇文章参考:
值传递 vs 指针传递 https://goinbigdata.com/golang-pass-by-pointer-vs-pass-by-value/ 值返回 vs 指针返回 https://philpearl.github.io/post/bad_go_pointer_returns/ |
22
xfriday 2022-03-25 19:43:12 +08:00
因为 go 没有 rust 的不可变借用
|
23
nightwitch 2022-03-25 21:17:58 +08:00
语言设计成值语义还是对象语义只是一种品味问题。
可以看看陈硕的文章: https://www.cnblogs.com/solstice/archive/2011/08/16/2141515.html 在默认对象语义的语言里,比如 Python 这种,想要复制一份值要显式的调用 copy.deepcopy(),否则可能在函数里意外地修改函数外变量的值,很容易创造隐藏的 bug 。 |
24
tomari 2022-03-25 21:44:54 +08:00
大一第一学期 C++课就说了啥时候传参用指针和引用,一是改变值,二是数据太大复制浪费时间和空间,依稀记得这个大一的期末考也会考。
|
25
cassyfar 2022-03-26 08:28:33 +08:00
这是 stackoverflow 大学毕业的吗?
|
26
Kasumi20 2022-03-26 15:34:12 +08:00
什么叫 go 设计出值传递, 所有的数据都是值, 包括指针也是 4 字节或者 8 字节的值, OK?
|
27
mengzhuo 2022-03-26 20:46:50 +08:00
可以,就是对其他程序员不好理解。
性能没差多少,倒是很好通过 channel 扩展。 |
28
349865361 2022-05-28 14:00:29 +08:00
我都是传递结构体的时候用引用,单变量不需要修改的直接传, 切片和 map 本身就有引用树形所以也直传
|