导读:本期聚焦于小伙伴创作的《Go中指针接收者与值接收者的本质区别是什么及使用场景有哪些》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Go中指针接收者与值接收者的本质区别是什么及使用场景有哪些》有用,将其分享出去将是对创作者最好的鼓励。

Go语言的方法定义支持两种接收者形式,分别是值接收者和指针接收者,这两种形式在底层实现、数据修改能力、内存开销等方面存在本质差异,不同的选择会直接影响代码的逻辑正确性和运行性能。

Go中指针接收者与值接收者的本质区别是什么及使用场景有哪些

一、指针接收者与值接收者的定义形式

值接收者的方法定义中,接收者是一个值类型的变量,而指针接收者的接收者是一个指针类型的变量,两者的语法差异如下:

package main

import "fmt"

// 定义结构体
type User struct {
	Name string
	Age  int
}

// 值接收者方法:接收者是User类型的值
func (u User) SetNameByValue(name string) {
	u.Name = name
}

// 指针接收者方法:接收者是*User类型的指针
func (u *User) SetNameByPointer(name string) {
	u.Name = name
}

func main() {
	user := User{Name: "张三", Age: 20}
	// 调用值接收者方法
	user.SetNameByValue("李四")
	fmt.Println("调用值接收者方法后:", user.Name) // 输出:张三
	// 调用指针接收者方法
	user.SetNameByPointer("李四")
	fmt.Println("调用指针接收者方法后:", user.Name) // 输出:李四
}

二、本质区别分析

1. 数据修改能力不同

值接收者在方法调用时会拷贝一份原结构体的副本,方法内部对接收者的修改仅作用于副本,不会影响原结构体实例;而指针接收者传递的是原结构体的内存地址,方法内部通过指针修改接收者的字段时,会直接修改原结构体的数据。

上述示例中已经体现了这一点,调用SetNameByValue后原userName字段没有变化,调用SetNameByPointer后原字段被成功修改。

2. 内存开销不同

值接收者调用方法时会发生结构体的拷贝,如果结构体体积较大,拷贝过程会带来额外的内存开销和性能损耗;指针接收者仅传递一个内存地址(在64位系统中占8字节),无论结构体多大,传递成本都是固定的,内存开销更小。

3. 方法集差异

Go语言的方法集规则决定了类型实现的接口范围:值类型的方法集仅包含值接收者方法,指针类型的方法集同时包含值接收者方法和指针接收者方法。这意味着如果结构体仅定义了值接收者方法,那么值实例和指针实例都可以调用这些方法;如果定义了指针接收者方法,那么只有指针实例可以实现对应的接口。

示例如下:

package main

import "fmt"

type Animal interface {
	Speak()
}

type Dog struct {
	Name string
}

// 值接收者方法
func (d Dog) Speak() {
	fmt.Println(d.Name + "汪汪叫")
}

// 指针接收者方法
func (d *Dog) Run() {
	fmt.Println(d.Name + "在跑")
}

func main() {
	var d1 Dog = Dog{Name: "小黑"}
	var d2 *Dog = &Dog{Name: "小白"}
	// d1和d2都可以调用值接收者方法
	d1.Speak()
	d2.Speak()
	// 只有d2可以调用指针接收者方法,d1调用会编译报错
	// d1.Run() // 编译错误
	d2.Run()
	// 实现Animal接口:d1和d2都可以,因为Dog有值接收者方法Speak
	var a1 Animal = d1
	var a2 Animal = d2
	a1.Speak()
	a2.Speak()
}

三、使用场景选择

适合使用值接收者的场景

  • 结构体体积较小,拷贝开销可以忽略,比如仅包含几个基础类型的结构体。
  • 方法不需要修改接收者的字段,仅需要读取数据。
  • 结构体是内置的不可变类型,比如time.Time,官方推荐使用该类型的值接收者。

适合使用指针接收者的场景

  • 方法需要修改接收者的字段或者状态。
  • 结构体体积较大,值拷贝会带来明显的性能损耗。
  • 结构体需要被多个地方共享修改,避免每次调用都产生副本。
  • 如果结构体中包含sync.Mutex等同步字段,必须使用指针接收者,避免拷贝导致锁失效。

四、常见注意事项

Go语言会自动对接收者进行取地址或者解引用操作,比如值实例调用指针接收者方法时,编译器会自动取实例的地址作为接收者;指针实例调用值接收者方法时,编译器会自动解引用指针得到值。但这一特性不能掩盖两者的本质差异,开发者在选择接收者时仍需要结合上述区别和场景判断。

注意:不要为了节省内存无脑使用指针接收者,如果结构体很小且不需要修改,值接收者的可读性和逻辑清晰度会更好,同时小对象的拷贝开销通常远低于指针带来的间接访问开销。

Go指针接收者值接收者方法接收者receiver修改时间:2026-07-22 20:36:25

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。