Using pointers vs copy in struct "functions"

huangapple go评论83阅读模式
英文:

Using pointers vs copy in struct "functions"

问题

我对Go语言还比较新手,对于在编写结构体函数时何时使用指针和何时使用副本,我真的无法决定(这个术语用得对吗?)。

type Blah struct {
    c complex128
    s string
    f float64
}

func (b *Blah) doPtr() {
    fmt.Println(b.c, b.s, b.f)
}

func (b Blah) doCopy() {
    fmt.Println(b.c, b.s, b.f)
}

根据我的C++背景,我认为doPtr在速度和内存方面都更高效,然而很多示例都使用doCopy,除非你要修改对象,所以我是否漏掉了什么?

英文:

I'm rather new to Go, and I really can't decide when to use a pointer vs a copy when writing struct "functions" (is that the proper term?)

type Blah struct {
	c complex128
	s string
	f float64
}

func (b * Blah) doPtr() {
	fmt.Println(b.c, b.s, b.f);
}

func (b Blah) doCopy() {
	fmt.Println(b.c, b.s, b.f);
}

Now, my C++ background tells me doPtr is more efficient in both speed and memory, however a lot of examples use doCopy unless you're modifying the object, so am I missing something?

答案1

得分: 8

[Go]常见问题(FAQ)

[在值上定义方法还是指针上定义方法?]

对于基本类型、切片和小型结构等类型,值接收器非常廉价,因此除非方法的语义要求使用指针,否则值接收器是高效和清晰的选择。

对于性能问题,不要猜测,而是运行基准测试。例如,

文件:bench_test.go

package main

import (
	"testing"
)

type Blah struct {
	c complex128
	s string
	f float64
}

func (b *Blah) doPtr() {
}

func (b Blah) doCopy() {
}

func BenchmarkDoPtr(b *testing.B) {
	blah := Blah{}
	for i := 0; i < b.N; i++ {
		(&blah).doPtr()
	}
}

func BenchmarkDoCopy(b *testing.B) {
	blah := Blah{}
	for i := 0; i < b.N; i++ {
		blah.doCopy()
	}
}

输出:

$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkDoPtr	2000000000	1.26 ns/op
BenchmarkDoCopy	50000000	32.6 ns/op
ok	so/test	4.317s
$

[1]: [Go] Frequently Asked Questions (FAQ)
[2]: Should I define methods on values or pointers?

英文:

> [Go] Frequently Asked Questions (FAQ)
>
> Should I define methods on values or pointers?
>
> For types such as basic types, slices, and small structs, a value
> receiver is very cheap so unless the semantics of the method requires
> a pointer, a value receiver is efficient and clear.

For performance issues, don't guess. Run a benchmark. For example,

file: bench_test.go

package main

import (
	&quot;testing&quot;
)

type Blah struct {
	c complex128
	s string
	f float64
}

func (b *Blah) doPtr() {
}

func (b Blah) doCopy() {
}

func BenchmarkDoPtr(b *testing.B) {
	blah := Blah{}
	for i := 0; i &lt; b.N; i++ {
		(&amp;blah).doPtr()
	}
}

func BenchmarkDoCopy(b *testing.B) {
	blah := Blah{}
	for i := 0; i &lt; b.N; i++ {
		blah.doCopy()
	}
}

Output:

$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkDoPtr	2000000000	         1.26 ns/op
BenchmarkDoCopy	50000000	        32.6 ns/op
ok  	so/test	4.317s
$

答案2

得分: 2

从《Go编程语言短语手册,第4章-作者David Chisnall》(在我看来,这是一本很好的书)中得到以下内容:

...另一个原因是这意味着该方法不需要接收结构体的指针。这非常重要,因为它与Go类型系统的关系。如果通过接口调用一个方法,那么只有当接口变量包含一个指针时,才能调用接受指针的方法。

例如,你可以定义一个接口,其中定义了Log()方法,并创建一个该类型的变量。然后,你可以将Logger结构体的实例分配给该变量。你也可以将Logger结构体的指针分配给该变量。两者都可以工作,因为Log()方法可以从结构体实例和结构体指针调用。如果该方法接受一个指针参数,那么你只能在指针上调用它。因此,在Go中,只有当方法修改结构体或者结构体太大以至于在每个方法调用时复制它是不可行的时,才需要方法接受一个指针,这是良好的编程风格...

英文:

From Go Programming Language Phrasebook, Chapter4 - by David Chisnall (IMO, an excellent book.)

...The other reason is that it means that this method does not need to take a pointer to the structure. This is quite important because of how it relates to the Go type system. If you call a method via an interface, then methods that accept a pointer are only callable if the interface variable contains a pointer.

For example, you could define an interface that defined the Log() method and create a variable of this type. Then you could assign an instance of the Logger structure to that variable. You could also assign a pointer to an instance of the Logger structure to this variable. Both would work, because the Log() method is callable from both instances of the structure and pointers to instances. If the method took a pointer argument, then you would only be able to call it on pointers. It’s therefore good style in Go to only require methods to take a pointer when they modify the structure, or if the structure is so large that copying it on every method call would be prohibitive...

huangapple
  • 本文由 发表于 2014年3月27日 18:39:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/22685062.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定