结构体作为函数(function)参数

Don't pass pointers as function arguments just to save a few bytes. If a function refers to its argumentxonly as *x throughout, then the argument shouldn't be a pointer. Common instances of this include passing a pointer to a string (*string) or a pointer to an interface value (*io.Reader). In both cases the value itself is a fixed size and can be passed directly. This advice does not apply to large structs, or even small structs that might grow.

翻译:不要为了节省几个字节而将指针作为函数参数传递。如果函数自始至终只将参数x引用为*x,则参数不应该是指针。常见的实例包括传递一个指向字符串的指针(*string)或一个指向接口值的指针(*io.Reader)。在这两种情况下,值本身都是固定大小,可以直接传递。此建议不适用于大型结构体,甚至可能增长的小型结构体。

大型结构体或者可能增长的结构体,可以考虑用指针传递。

结构体作为方法(method)中的接收器(receiver)

Choosing whether to use a value or pointer receiver on methods can be difficult, If in doubt, use a pointer, but there are times when a value receiver makes sense, usually for reasons of efficiency, such as for small unchanging structs or values of basic type. Some useful guidelines:
If the receiver is a map, func or chan, don't use a pointer to them. If the receiver is a slice and the method doesn't reslice or reallocate the slice, don't use a pointer to it.
If the method needs to mutate the receiver, the receiver must be a pointer.
If the receiver is a struct that contains a sync.Mutex or similar synchronizing field, the receiver must be a pointer to avoid copying.
If the receiver is a large struct or array, a pointer receiver is more efficient. How large is large? Assume it's equivalent to passing all its elements as arguments to the method. If that feels too large, it's also too large for the receiver.
Can function or methods, either concurrently or when called from this method, be mutating the receiver? A value type creates a copy of the receiver when the method is invoked, so outside updates will not be applied to this receiver. If changes must be visible in the original receiver, the receiver must be a pointer.
If the receiver is a struct, array or slice and any of its elements is a pointer to something that might be mutating, prefer a pointer receiver, as it will make the intention clearer to the reader.
If the receiver is a small array or struct that is naturally a value type (for instance, something like the time.Time type), with no mutable fields and no pointers, or is just a simple basic type such as int or string, a value receiver makes sense. A value receiver can reduce the amount of garbage that can be generated; if a value is passed to a value method, an on-stack copy can be used instead of allocating on the heap. (The compiler tries to be smart about avoiding this allocation, but it can't always succeed.) Don't choose a value receiver type for this reason without profiling first.
Don't mix receiver types. Choose either pointers or struct types for all available methods.
Finally, when in doubt, use a pointer receiver.

翻译:在方法上选择是使用值接收器还是指针接收器可能很困难,如果有疑问,就使用指针,但有时值接收器是有意义的,通常是出于效率的原因,例如对于小的不变结构体或基本类型的值。

  • 如果接收器是map、func或chan,不要使用指向它们的指针。如果接收方是一个切片,而该方法没有切片或重新分配该切片,则不要使用指向它的指针。
  • 如果方法需要改变接收器,接收器必须是一个指针。
  • 如果接收器是一个包含同步的结构体。互斥锁或类似的同步字段,接收方必须是一个指针,以避免复制。
  • 如果接收器是一个大型结构体或数组,则指针接收器的效率更高。
  • 函数或方法(无论是并发地还是从该方法调用时)是否会改变接收器?当调用方法时,值类型会创建接收方的副本,因此外部更新不会应用于此接收方。如果更改必须在原始接收器中可见,则接收器必须是一个指针。
  • 如果接收方是结构体、数组或切片,并且其任何元素都是指向可能发生变化的对象的指针,那么最好是接收方指针,因为它将使读者更清楚地了解意图。
  • 如果接收方是一个小数组或结构体,它自然是一个值类型(例如,时间之类的东西)。时间类型),没有可变字段和指针,或者只是一个简单的基本类型,如int或string,值接收器是有意义的。值接收器可以减少可以生成的垃圾数量;如果将一个值传递给value方法,则可以使用堆栈上的副本,而不是在堆上分配。(编译器试图聪明地避免这种分配,但它并不总是成功。)因此,在没有进行分析之前,不要选择值接收器类型。
  • 不要混合接收类型。为所有可用的方法选择指针或结构类型。
  • 最后,当不知道选择值接收器还是指针接收器时,使用指针接收器。

参考