方法接收者的值类型和指针类型有什么区别?
2024-01-30 20:42:28
在Go中,结构体方法的接收者可以是一个值类型,也可以是一个指针类型。对于这个小知识点,你是否早已熟记于心呢?如果没有,且听我一一道来。
先简单了解方法接收者的值类型
当一个结构体方法的接收者是值类型时,在方法中对结构体进行修改时,不会影响到结构体本身。这是因为,在Go中,结构体是值类型。当一个结构体被传递给一个函数时,函数会创建一个结构体的副本,然后在这个副本上进行操作。因此,对副本的任何修改都不会影响到原来的结构体。
例如,假设我们有一个名为Person
的结构体,它有两个字段:name
和age
。我们还可以为Person
结构体定义一个名为SetName
的方法,该方法接收一个值类型的Person
结构体作为参数,并将该结构体的name
字段设置为一个新值。
type Person struct {
name string
age int
}
func (p Person) SetName(name string) {
p.name = name
}
现在,假设我们创建一个Person
结构体的实例,并将它的name
字段设置为"John Doe"
。
person := Person{"John Doe", 30}
然后,我们调用SetName
方法,并将person
结构体的name
字段设置为"Jane Doe"
。
person.SetName("Jane Doe")
此时,person
结构体的name
字段的值为"Jane Doe"
。但是,原来的Person
结构体的name
字段的值仍然是"John Doe"
。这是因为,在SetName
方法中,我们对person
结构体的name
字段进行修改时,实际上是对person
结构体的副本的name
字段进行修改。
再深入了解方法接收者的指针类型
当一个结构体方法的接收者是指针类型时,在方法中对结构体进行修改时,会影响到结构体本身。这是因为,在Go中,指针是引用类型。当一个指针被传递给一个函数时,函数会得到指向该指针所指向的内存地址的引用。因此,对指针的任何修改都会影响到指针所指向的内存地址的内容。
例如,假设我们有一个名为Person
的结构体,它有两个字段:name
和age
。我们还可以为Person
结构体定义一个名为SetName
的方法,该方法接收一个指针类型的Person
结构体作为参数,并将该结构体的name
字段设置为一个新值。
type Person struct {
name string
age int
}
func (p *Person) SetName(name string) {
p.name = name
}
现在,假设我们创建一个Person
结构体的实例,并将它的name
字段设置为"John Doe"
。
person := Person{"John Doe", 30}
然后,我们调用SetName
方法,并将person
结构体的name
字段设置为"Jane Doe"
。
(&person).SetName("Jane Doe")
此时,person
结构体的name
字段的值为"Jane Doe"
。而且,原来的Person
结构体的name
字段的值也为"Jane Doe"
。这是因为,在SetName
方法中,我们对person
结构体的name
字段进行修改时,实际上是对person
结构体本身的name
字段进行修改。
哪种类型的接收者更合适?
那么,在实际开发中,我们应该使用值类型的接收者还是指针类型的接收者呢?这取决于具体的情况。
如果我们希望对结构体进行修改,并且希望这些修改能够影响到结构体本身,那么我们应该使用指针类型的接收者。例如,如果我们有一个名为Person
的结构体,它有一个名为age
的字段,并且我们希望对age
字段进行自增操作,那么我们应该使用指针类型的接收者。
type Person struct {
age int
}
func (p *Person) IncrementAge() {
p.age++
}
如果我们不希望对结构体进行修改,或者我们希望对结构体进行修改,但是不希望这些修改影响到结构体本身,那么我们应该使用值类型的接收者。例如,如果我们有一个名为Person
的结构体,它有两个字段:name
和age
,并且我们希望获取name
字段的值,那么我们应该使用值类型的接收者。
type Person struct {
name string
age int
}
func (p Person) GetName() string {
return p.name
}