当前位置: 首页 > news >正文

Go赋值操作的关键细节

一、:=短变量声明的细节

1.作用域规则

2.重复声明规则

3类型推断

二、 =赋值操作的细节

1.类型必须匹配

2.多重赋值特性

三、 零值初始化细节

1.Go为所有类型提供零值

四、指针赋值的细节

1.基本指针操作

理解这段代码的关键在于搞清楚两个概念:普通变量指针变量,以及它们之间的关系。

用“门牌号”和“房子”来理解

  • 变量x就像是一栋房子,里面住着数字10

  • 指针变量p就像是一张纸条,上面写着这栋房子的门牌号(内存地址)

现在看代码的每一步:

var x int = 10
var p *int = &x

1.建房子x盖好了,里面放了10

2.写纸条p是张空白纸条,&x就是去查x的门牌号,然后把门牌号p的纸条上。

*p = 20

3.改房子里的东西

  • *p这个动作,叫解引用

  • 意思是:拿起p这张纸条,顺着上面的门牌号找到x这栋房子,然后把里面的东西换成20

  • 注意:纸条没变(还是那个门牌号),但房子里的东西变了

fmt.Println(x) // 输出 20

4.结果x这栋房子里的内容已经是20了。因为px指向的是同一栋房子,所以通过p改,x自己也会变。

为什么var q *int危险?

var q *int
// *q = 30 // ❌ 这里会崩溃

  • q是一张空白纸条nil指针)

  • 纸上没有写任何门牌号

  • 如果执行*q = 30,就相当于:

    “拿着一张空白纸条去找房子,强行往里面塞东西。”

你根本不知道那个房子在哪儿(内存地址无效),操作系统为了保护其他程序的安全,会直接终止程序(Panic)

2.结构体指针

五、特殊赋值情况

1.空白标识符 _

2.常量赋值

六、复合类型的赋值细节

1.切片赋值

2.映射赋值

七、 函数相关的赋值细节

1.命名返回值

一旦起了名字,这两个变量在函数一开始就被自动创建并初始化为零值result=0,err=nil)。

当你写一个return(后面不带东西)时,Go 就默认:“把当前resulterr的值,原样打包返回给调用方。”

场景一:b == 0(出错)

  1. 进入函数,Go 自动创建result=0,err=nil

  2. 检测到b == 0,执行err = errors.New(...)

  3. 执行裸return。此时result还是0err是新错误。

  4. 返回:(0, error)

场景二:b != 0(正常)

  1. 进入函数,Go 自动创建result=0,err=nil

  2. 跳过if,执行result = a / b

  3. 执行裸return。此时result是计算结果,err还是nil

  4. 返回:(计算结果, nil)

2.闭包中的变量捕获

为什么错误写法里,所有函数都输出3i不是每次循环都在变吗?

闭包捕获的是变量本身,不是当时的值
  • 在错误写法中,for循环里的i同一个变量

  • 每次循环,只是修改了这个变量的值(0 → 1 → 2 → 3 循环结束)。

  • 闭包函数func(){ fmt.Println(i) }记住的是i这个变量本身(门牌号),而不是创建时的数值。

  • 等到你真正执行这些函数时(比如f := funcs[0]; f()),循环早就结束了,i已经变成了3

i := i到底干了什么?
  • 左边的i:创建一个全新的、局部的变量(作用域仅在本次循环内)。

  • 右边的i:是外层for循环的变量。

  • 效果:把外层i当前的值复制给内层新的i

  • 结果:闭包捕获的是这个全新的内层变量,它只属于这一次循环,下次循环会再创建另一个新的。

  • funcs := make([]func(), 0)相当于:你买了一个空的 “待办事项清单” 本子

  • funcs = append(funcs, func(){...})相当于:往这个本子里 “记下一条新任务”

核心连接点:类型func()

这两行代码能配合工作的唯一桥梁就是括号里的类型func()

代码片段中文直译关键细节
make([]func(), 0)制作一个切片,这个切片只能用来存放func()类型的东西指明了仓库的“货架规格”。
func(){ fmt.Println(i) }这是一个匿名函数,它的签名正是func()(无参数、无返回值)。生产了一个符合“货架规格”的货物。
append(funcs, ...)把货物放到货架上。类型必须严格匹配,否则编译报错。

如果把它们拆成三个时间点来看,逻辑会更清晰:

// 第一步:声明与初始化(建立空仓库) // 此时 funcs 的长度为 0,容量为 0,里面一个函数都没有。 funcs := make([]func(), 0) // 第二步:循环制造与入库(append 操作) for i := 0; i < 3; i++ { // 此时生成了一个匿名函数对象(货物) // append 函数检查:这个货物是不是 func() 类型? ✅ 是的。 // 于是 append 将 funcs 扩容,并把货物放在索引位置。 funcs = append(funcs, func() { fmt.Println(i) }) } // 第三步:此时 funcs 变成了一个有 3 个元素的切片 // 结构类似于:[ 函数0 , 函数1 , 函数2 ]

为什么要用=接收?

你可能会注意到写的是funcs = append(...)而不是单纯的append(...)

这是因为Go 的切片在扩容时,底层数组的地址可能会变(搬仓库)。append函数会把新仓库的地址作为返回值返回。如果你不用funcs =接住它,你就失去新仓库的钥匙了,funcs还是指向那个旧的、没扩容的空仓库。

避免的陷阱

总结:

http://www.cnnetsun.cn/news/1806484.html

相关文章:

  • 如何为波斯语项目选择完美的开源字体?Behdad字体深度解析与实战指南
  • Java生产者消费者模式实战解析
  • 别再数据线了!用FastAPI 分钟搭个局域网文件+剪贴板神器谓
  • 冷库维护上门服务全攻略:这些疑问你肯定也有
  • Speechless:终极微博备份指南 - 如何3分钟将微博内容安全导出为PDF
  • AlmaLinux构建LNMP
  • SITS2026架构白皮书解密:为什么92%的传统Serverless团队将在2026年前被迫重构?
  • DLT645-2007协议常见报文错误排查指南:从校验失败到数据域乱码
  • 算法·贪心
  • AI原生DevOps流水线重构(奇点大会闭门报告节选):CI/CD→AI/CD的8项指标迁移清单
  • 揭秘2026奇点智能技术大会核心成果:如何用AI原生审查引擎将PR平均审核时长从47分钟压缩至93秒?
  • Windows任务栏个性化定制完全指南:7+ Taskbar Tweaker使用教程
  • RESTful API设计完整手册:http-api-guide最佳实践
  • LCD显示屏接口
  • 老马失前蹄,竟然在数据库外键上翻车了,重温外键级联巡
  • STC8H单片机学习-GPIO的四种模式
  • 轴承故障诊断避坑指南:东南大学数据集实战中,80%的人会忽略的GAF参数设置与模型调优细节
  • YOLOv11新版本解读:结合Phi-4-mini-reasoning分析技术演进与适用场景
  • 如何快速配置炉石传说智能脚本:新手的完整入门攻略
  • Bilibili-Evolved:终极B站增强脚本的完整指南
  • 如何免费实现PotPlayer字幕在线翻译:百度翻译插件完整指南
  • 前端可访问性:别让你的应用变成残疾人的噩梦
  • YOLOv5+DeepSORT实战:从零搭建目标检测与跟踪系统(含代码优化)
  • 【书生·浦语】internlm2-chat-1.8b在医疗健康领域应用:症状自查与报告解读
  • Cursor Pro破解全攻略:简单三步实现AI编程神器永久免费使用终极指南
  • CosyVoice语音生成大模型-300M-25Hz学术应用:配合MathType公式的理工科教学音频生成
  • RTX4090D专属Qwen-Image镜像:电商商品识别与图文问答实战
  • 5分钟极速上手:华硕笔记本终极性能控制工具G-Helper完全指南
  • 终极指南:如何用VideoSrt为视频快速生成专业字幕
  • 直驱永磁风机并网Chopper低电压穿越的Matlab Simulink仿真