您现在的位置是:首页 >学无止境 >golang中的指针方法和值方法的区别,编程时该如何选择呢?网站首页学无止境

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

麦田里的守望者_zhg 2024-10-12 12:01:03
简介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
", c1.GetName())   // ""
	fmt.Printf("c2: %s
", c2.GetNameV2()) // "cat2"

	var c3, c4 *Cat
	c3 = &Cat{}
	c4 = &Cat{}
	c3.SetName("cat3")
	c4.SetNameV2("cat4")
	fmt.Printf("c3: %s
", c3.GetName())   // ""
	fmt.Printf("c4: %s
", 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
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。