在结构“函数”中使用指针与复制

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?

[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 (
    "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()
    }
}

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
$

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...