MST

星途 面试题库

面试题:Go 类型方法中值接收者与指针接收者的区别

在 Go 语言中,类型方法可以使用值接收者或指针接收者。请阐述这两种接收者在使用场景、内存操作以及方法调用特性上有什么区别?并举例说明在什么情况下应该选择值接收者,什么情况下应该选择指针接收者。
11.4万 热度难度
编程语言Go

知识考点

AI 面试

面试题答案

一键面试

使用场景

  • 值接收者:适用于方法不改变接收者状态,并且接收者本身比较小(如基本类型、小型结构体)的场景。它是对接收者值的拷贝进行操作,原接收者不受影响。
  • 指针接收者:适用于方法需要改变接收者状态,或者接收者是大型结构体,使用指针可以避免大量的数据拷贝,提高效率。

内存操作

  • 值接收者:每次方法调用时会复制接收者的值,因此如果接收者是大型结构体,会占用较多内存,效率较低。
  • 指针接收者:方法调用时传递的是指针,只需要复制指针大小的内存(通常是 4 字节或 8 字节),不会复制整个结构体,节省内存,适合大型结构体。

方法调用特性

  • 值接收者:值类型变量既可以调用值接收者方法,也可以调用指针接收者方法(Go 语言会自动进行转换)。
  • 指针接收者:指针类型变量既可以调用指针接收者方法,也可以调用值接收者方法(Go 语言会自动进行转换)。但是如果使用值类型调用指针接收者方法,Go 语言会自动取地址;如果使用指针类型调用值接收者方法,Go 语言会自动解引用。

示例

package main

import "fmt"

// 定义一个小型结构体
type SmallStruct struct {
    Value int
}

// 值接收者方法
func (s SmallStruct) ValueMethod() {
    s.Value++
    fmt.Printf("值接收者方法中 s.Value: %d\n", s.Value)
}

// 指针接收者方法
func (s *SmallStruct) PointerMethod() {
    s.Value++
    fmt.Printf("指针接收者方法中 s.Value: %d\n", s.Value)
}

func main() {
    small := SmallStruct{Value: 10}
    // 值类型调用值接收者方法
    small.ValueMethod()
    fmt.Printf("调用值接收者方法后 small.Value: %d\n", small.Value)

    // 值类型调用指针接收者方法,Go 语言自动取地址
    small.PointerMethod()
    fmt.Printf("调用指针接收者方法后 small.Value: %d\n", small.Value)

    smallPtr := &SmallStruct{Value: 20}
    // 指针类型调用值接收者方法,Go 语言自动解引用
    smallPtr.ValueMethod()
    fmt.Printf("调用值接收者方法后 smallPtr.Value: %d\n", smallPtr.Value)

    // 指针类型调用指针接收者方法
    smallPtr.PointerMethod()
    fmt.Printf("调用指针接收者方法后 smallPtr.Value: %d\n", smallPtr.Value)
}

选择场景

  • 选择值接收者:当方法不需要修改接收者状态,并且接收者本身是基本类型或者小型结构体时,选择值接收者。例如,计算一个整数的平方的方法,可以使用值接收者。
type Number int

func (n Number) Square() Number {
    return n * n
}
  • 选择指针接收者:当方法需要修改接收者状态,或者接收者是大型结构体时,选择指针接收者。例如,向一个大型用户信息结构体中添加新的联系方式的方法,应该使用指针接收者。
type User struct {
    Name       string
    Age        int
    Contacts   []string
}

func (u *User) AddContact(contact string) {
    u.Contacts = append(u.Contacts, contact)
}