golang中的指针方法和值方法的区别,编程时该如何选择呢?

1 方法

我们都知道,方法的接收者类型必须是某个自定义的数据类型,而且不能是接口类型或接口的指针类型。所谓的值方法,就是接收者类型是非指针的自定义数据类型的方法。

package main

import "fmt"

type Cat struct {
	Name string
}

func (c Cat) SetName(s string) {
	c.Name = s
}

func (c Cat) GetName() string {
	return c.Name
}

func (c *Cat) SetNameV2(s string) {
	c.Name = s
}

func (c *Cat) GetNameV2() string {
	return c.Name
}

func main() {
	var c1, c2 Cat
	c1.SetName("cat1")                     // 等价于 (&c1).SetName("cat1")
	c2.SetNameV2("cat2")                   // 等价于 (&c2).SetNameV2("cat2")
	fmt.Printf("c1: %s\n", c1.GetName())   // ""
	fmt.Printf("c2: %s\n", c2.GetNameV2()) // "cat2"

	var c3, c4 *Cat
	c3 = &Cat{}
	c4 = &Cat{}
	c3.SetName("cat3")
	c4.SetNameV2("cat4")
	fmt.Printf("c3: %s\n", c3.GetName())   // ""
	fmt.Printf("c4: %s\n", c4.GetNameV2()) // "cat4"
}

值方法和指针方法使用技巧

Choosing whether to use a value or pointer receiver on methods can be difficult, especially to new Go programmers. 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.

Reference

  1. https://crazyjums-1.gitbook.io/36-lectures-on-golang/13-jie-gou-ti-ji-qi-fang-fa-de-shi-yong-fa-men
  2. https://zhuanlan.zhihu.com/p/101363361
  3. https://github.com/golang/go/wiki/CodeReviewComments#receiver-type
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值