2 回答

TA贡献1829条经验 获得超13个赞
在函数调用中,函数值和参数按通常的顺序计算。在对它们求值后,调用的参数按值传递给函数,被调用的函数开始执行。当函数返回时,函数的返回参数按值传递回调用函数。
接收器sm some按值传递给方法,当您从方法返回时,副本将被丢弃。使用指针接收器。
例如,
package main
import (
"fmt"
"sync/atomic"
)
type some struct {
I uint32
}
func (sm *some) Add1() {
atomic.AddUint32(&sm.I, 1)
}
func main() {
var s some
s.Add1()
fmt.Println(s)
}
输出:
{1}
与 C 系列中的所有语言一样,Go 中的所有内容都是按值传递的。也就是说,一个函数总是得到一个被传递的东西的副本,就好像有一个赋值语句给参数赋值一样。例如,将 int 值传递给函数会生成 int 的副本,而传递指针值会生成指针的副本,但不是它指向的数据的副本。
func (s *MyStruct) pointerMethod() { } // method on pointer func (s MyStruct) valueMethod() { } // method on value
对于不习惯指针的程序员来说,这两个例子之间的区别可能会令人困惑,但情况其实很简单。在类型上定义方法时,接收器(在上面的示例中为 s)的行为就像它是方法的参数一样。将接收者定义为值还是指针是同一个问题,那么,函数参数应该是值还是指针。有几个考虑。
首先,也是最重要的,该方法是否需要修改接收器?如果是,则接收者必须是一个指针。(切片和映射充当引用,所以它们的故事有点微妙,但是例如要更改方法中切片的长度,接收者仍然必须是指针。)在上面的示例中,如果 pointerMethod 修改了s,调用者将看到这些更改,但 valueMethod 是使用调用者参数的副本调用的(这是传递值的定义),因此调用者将看不到它所做的更改。
顺便说一句,指针接收器与 Java 中的情况相同,尽管在 Java 中指针隐藏在幕后;Go 的价值接收者是不寻常的。
二是对效率的考虑。如果接收器很大,例如一个大的结构,使用指针接收器会便宜得多。
接下来是一致性。如果该类型的某些方法必须有指针接收器,其余的也应该如此,因此无论如何使用该类型,方法集都是一致的。有关详细信息,请参阅方法集部分。
对于诸如基本类型、切片和小型结构之类的类型,值接收器非常便宜,因此除非方法的语义需要指针,否则值接收器是高效且清晰的。

TA贡献1875条经验 获得超5个赞
您的函数需要接收要递增的值的指针,这样您就不会传递结构的副本,并且在下一次迭代中 I 可以递增。
package main
import (
"sync/atomic"
"fmt"
)
type some struct{
I uint32
}
func main() {
q := &some{0}
for i := 0; i < 10; i++ {
q.Add1()
fmt.Println(q.I)
}
}
func (sm *some) Add1(){
atomic.AddUint32(&sm.I,1)
}
- 2 回答
- 0 关注
- 175 浏览
添加回答
举报