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 还是指向那个旧的、没扩容的空仓库。

避免的陷阱

总结:

相关推荐
wechat_Neal1 天前
Golang的车载应用场景
开发语言·后端·golang
weixin_513449961 天前
walk_these_ways项目学习记录第八篇(通过行为多样性 (MoB) 实现地形泛化)--策略网络
开发语言·人工智能·python·学习
飞Link1 天前
逆向兼容的桥梁:3to2 自动化降级工具实现全解析
运维·开发语言·python·自动化
曾阿伦1 天前
Python3 文件 (夹) 操作备忘录
开发语言·python
dong__csdn1 天前
jdk添加信任证书
java·开发语言
南 阳1 天前
Python从入门到精通day64
开发语言·python
Wenweno0o1 天前
Eino-Graph 实战详解
golang·智能体·eino
花千树-0101 天前
Java 接入多家大模型 API 实战对比
java·开发语言·人工智能·ai·langchain·ai编程
上海合宙LuatOS1 天前
LuatOS扩展库API——【exremotecam】网络摄像头控制
开发语言·网络·物联网·lua·luatos
feng_you_ying_li1 天前
C++11,{}的初始化情况与左右值及其引用
开发语言·数据结构·c++