0

0

Go 中方法接收者使用指针()与值语义的关键区别

碧海醫心

碧海醫心

发布时间:2026-01-08 21:36:03

|

313人浏览过

|

来源于php中文网

原创

Go 中方法接收者使用指针()与值语义的关键区别

go 中,方法接收者前加 `*` 表示该方法作用于结构体指针,操作的是原始数据;不加 `*` 则作用于结构体副本,修改不会影响原值。虽然只读操作效果相同,但涉及字段修改、性能优化或接口实现时,二者行为截然不同。

在 Go 的面向对象设计中,“接收者”(receiver)决定了方法是绑定到值还是指针。以 func (h *Human) SayHi() 为例,*Human 表示该方法只能被 *Human 类型(即 Human 指针)调用;而 func (h Human) SayHi() 则绑定到 Human 值类型,每次调用都会复制整个结构体。

? 关键差异:是否可修改原始数据?

下面通过一个明确的对比示例说明:

func (h *Human) UpdateName(newName string) {
    h.name = newName // ✅ 修改成功:作用于原始结构体
}

func (h Human) TryUpdateName(newName string) {
    h.name = newName // ❌ 无效:仅修改副本,原值不变
}

完整验证代码:

360鸿图
360鸿图

360公司推出的AI绘画生成工具

下载
package main
import "fmt"

type Human struct {
    name string
    age  int
}

func (h *Human) UpdateNamePtr(newName string) {
    h.name = newName
}

func (h Human) UpdateNameVal(newName string) {
    h.name = newName // 编译通过,但无实际效果
}

func main() {
    person := Human{name: "Alice", age: 30}

    fmt.Printf("Before: %+v\n", person) // {name:Alice age:30}

    person.UpdateNamePtr("Bob")   // ✅ 成功更新
    fmt.Printf("After ptr-call: %+v\n", person) // {name:Bob age:30}

    person.UpdateNameVal("Charlie") // ❌ 无影响
    fmt.Printf("After val-call: %+v\n", person) // {name:Bob age:30} — 仍是 Bob
}

⚙️ 其他重要考量

  • 性能:对于大型结构体(如含切片、map 或大量字段),使用指针接收者避免不必要的内存拷贝,显著提升效率。
  • 一致性与接口实现:若某类型已存在指针接收者方法(如 (*Human).SayHi),则只有 *Human 能满足接口要求;Human 值类型无法实现同一接口(除非所有方法均为值接收者)。
  • 嵌入字段的调用链:在 Student 或 Employee 中调用 SayHi() 时,Go 会自动解引用(如 mark.SayHi() → mark.Human.SayHi())。但若 SayHi 是值接收者,Student{} 字面量仍可调用;若为指针接收者,只要 Human 字段可寻址(如变量而非字面量临时值),Go 仍能自动取地址——这是语言层面的便利特性,不改变接收者语义本身
  • 并发安全提示:如答案中指出,若多个 goroutine 同时调用指针接收者方法并修改字段,需额外加锁;而值接收者天然“线程安全”(因操作副本),但代价是无法持久化变更。

✅ 最佳实践建议

  • 若方法需修改接收者字段 → 必须使用 *T 接收者;
  • 若结构体较大(> few dozen bytes)→ 优先用 *T 避免拷贝;
  • 若类型需实现某个接口,且该接口已有指针方法 → 统一使用 *T;
  • 若纯只读、小结构体、且明确不需要修改 → T 亦可,语义更清晰。

简言之:* 不是语法装饰,而是 Go 显式区分“操作本体”与“操作副本”的核心机制——理解它,是写出可维护、高性能 Go 代码的第一步。

相关专题

更多
go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

54

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

49

2025.11.27

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

194

2025.06.09

golang结构体方法
golang结构体方法

本专题整合了golang结构体相关内容,请阅读专题下面的文章了解更多。

186

2025.07.04

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1007

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

57

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

350

2025.12.29

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

476

2023.08.10

php学习网站大全
php学习网站大全

精选多个优质PHP入门学习网站,涵盖教程、实战与文档,适合零基础到进阶开发者,助你高效掌握PHP编程。

0

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 3.5万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号