返回

方法接收者的值类型和指针类型有什么区别?

后端

在Go中,结构体方法的接收者可以是一个值类型,也可以是一个指针类型。对于这个小知识点,你是否早已熟记于心呢?如果没有,且听我一一道来。

先简单了解方法接收者的值类型

当一个结构体方法的接收者是值类型时,在方法中对结构体进行修改时,不会影响到结构体本身。这是因为,在Go中,结构体是值类型。当一个结构体被传递给一个函数时,函数会创建一个结构体的副本,然后在这个副本上进行操作。因此,对副本的任何修改都不会影响到原来的结构体。

例如,假设我们有一个名为Person的结构体,它有两个字段:nameage。我们还可以为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的结构体,它有两个字段:nameage。我们还可以为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的结构体,它有两个字段:nameage,并且我们希望获取name字段的值,那么我们应该使用值类型的接收者。

type Person struct {
    name string
    age  int
}

func (p Person) GetName() string {
    return p.name
}