如果您是 Go 新手,那么您一定遇到过方法和函数的概念。让我们找出两者之间的区别-
通过指定参数的类型、返回值和函数体来声明函数。
type Person struct {
Name string
Age int
}func NewPerson(name string, age int) *Person {
return &Person{
Name: name,
Age: age,
}
}
方法只是一个带有接收器参数的函数。它使用相同的语法声明,并添加了接收者。
func (p *Person) isAdult bool {
return p.Age > 18
}
在上面的方法声明中,我们在类型上声明了isAdult
方法。*Person
现在我们将看到值接收器和指针接收器之间的区别。
值接收者复制类型并将其传递给函数。函数堆栈现在拥有一个相等的对象,但在内存上的不同位置。这意味着对传递的对象所做的任何更改都将保留在该方法的本地。原始对象将保持不变。
指针接收器将类型的地址传递给函数。函数堆栈具有对原始对象的引用。因此对传递对象的任何修改都会修改原始对象。
让我们通过示例来理解这一点-
package main
import (
"fmt"
)
type Person struct {
Name string
Age int
}
func ValueReceiver(p Person) {
p.Name = "John"
fmt.Println("Inside ValueReceiver : ", p.Name)
}
func PointerReceiver(p *Person) {
p.Age = 24
fmt.Println("Inside PointerReceiver model: ", p.Age)
}
func main() {
p := Person{"Tom", 28}
p1:= &Person{"Patric", 68}
ValueReceiver(p)
fmt.Println("Inside Main after value receiver : ", p.Name)
PointerReceiver(p1)
fmt.Println("Inside Main after value receiver : ", p1.Age)
}
------------
Inside ValueReceiver : John
Inside Main after value receiver : Tom
Inside PointerReceiver : 24
Inside Main after pointer receiver : 24
这表明具有值接收者的方法修改了对象的副本,而原始对象保持不变。Like- 通过 ValueReceiver 方法将一个人的姓名从 Tom 更改为 John,但这种更改并未反映在 main 方法中。另一方面,带有指针接收器的方法会修改实际对象。Like- 通过 PointerReceiver 方法将人的年龄从 68 岁更改为 24 岁,同样的变化反映在 main 方法中。您可以通过在指针或值接收器操作之前和之后打印出对象的地址来检查事实。
那么如何在 Pointer 和 Value 接收器之间进行选择呢?
如果要更改方法中接收器的状态,操作它的值,请使用指针接收器。使用按值复制的值接收器是不可能的。对值接收器的任何修改对于该副本都是本地的。如果您不需要操作接收器值,请使用值接收器。
指针接收器避免在每个方法调用上复制值。如果接收器是一个大型结构,这可能会更有效,
值接收器是并发安全的,而指针接收器不是并发安全的。因此,程序员需要照顾它。
sync.Mutex
或类似同步字段的结构,则接收者必须是指针以避免复制。time.Time
类型),没有可变字段和指针,或者只是一个简单的基本类型,如 int 或 string,则值接收器更好。
值接收器可以减少可以生成的垃圾量;如果将值传递给值方法,则可以使用堆栈上的副本而不是在堆上分配。(编译器试图巧妙地避免这种分配,但它并不总是成功。)不要在没有首先进行分析的情况下选择值接收器类型。原文: https://medium.com/globant/go-method-receiver-pointer-vs-value-ffc5ab7acdb