go语法(简洁)
Go 核心语法精简笔记 (背诵/速查版)
核心红线:
声明了不用的变量、导入了不用的包,极必编译报错!
1. 变量与常量初始化
🌈 变量定义
1 | // 1. 标准声明 |
🌈 常量与iota枚举
常量的核心:运行期间绝对不能被改变,且必须在编译时就能确定类型值。
1 | // 1. 普通声明 |
2. 基础内置数据类型
🌈 数字与布尔
- 布尔值
bool:true和false。(⚠️ C++ 那一套0/1和空字符串当条件的技巧,在 Go 完全行不通) - 整型
int:会根据操作系统自适应变成 32/64 位。(定长型有:int32/int64) - 浮点数
float64:Go 省略小数类型时的默认推断类型。
🌈 字符串与字符
- 字符(单引号
''):byte(等同uint8) —— 存 ASCII 纯英文。rune(等同int32) —— 存 Unicode(中文汉字)。
- 字符串(双引号
""/ 反引号``):- ⚠️ 切记字符串不可修改! 不能
s[0] = 'H'。 - 必须转切片修改:
b := []rune(s) -> 修改 b -> string(b) - 💡 高频拼接用
strings.Builder,性能远大于+。
- ⚠️ 切记字符串不可修改! 不能
3. 分支控制流
⚠️ Go 语言中没有
a ? b : c三元运算符。
⚠️a++只能当一行的独立语句,不能放进式子算数,也没++a。
🌈 if 条件
好处是自带初始化,将变量作用域锁死在 if 内部。
1 | if a := 10; a > 0 { |
🌈 switch 分支
- 匹配即退出,不再需要手写
break。 case 1, 2, 3:支持单行并列多个条件。- 想强制穿透执行紧跟的下一个分支:加
fallthrough。 - Type Switch (给空接口探明真身):
switch v := interface变量.(type)
4. Struct 结构与 OOP
Go 虽然没有面向对象的 Class 类系统,但是利用结构体加方法函数完美承接。
💡 首字母大写公开可见,小写私有。
🌈 定义与初始化
1 | type Student struct { |
🌈 方法接收者(继承的原理)
把普通函数前面塞个括弧 (s Student) 就成了方法。
1 | // 1. 值接收者(拿的是副本,怎么改原本对象都不受影响) |
🌈 组合 (替代继承机制)
在结构体里嵌个别的结构体且不给起名字。如果有重命名的功能,外层优先遮蔽里层。
1 | type Animal struct { Name string } |
5. 数组与切片 (Slice)
🌈 核心区分
- 数组 定长!
[3]int和[4]int是两种完全不兼容的异度类型。 - 切片 引用型不定长数组视角,靠
make生成:make([]int, 长度, 容量)
🌈 扩容解绑大坑 ⚠️
通过 s[low : high] 取一段范围出来造的切片,一旦遭遇 append() 数据且原切片容量已经爆满了需要系统自动扩容时:
系统会强制拿走老数据在新地方重开辟一个豪华新大底。此后这个新切片跟原来的底子数组彻底一刀两断恩断义绝,修改互不干涉。
6. Map 字典集
⚠️ Map是超级容易 Panic 挂程序的祖宗!只声明是空指针
nil绝对不能存数据!
🌈 正确的创建与判空
1 | // 必须做 make ! |
🌈 Map 严格规定 ⚠️
- 你休想用
==判断两个 Map 里面长得一模一样。 - 能拿来给 Map 做前面那个 Key 头的,绝不能是:
slice 动态切片、map 字典、func 函数。
7. for 循环与 Range 陷阱
Go的循环只有一个 for 关键字打天下。
不再提旧三段式,着重提醒专门给切片Map配套遍历的黑科技:for range
🌈 Range 是值拷贝!修改无效 ⚠️
1 | s := []int{1, 2, 3} |
8. 函数值传递与真假指针
🌈 统一都是值传递!
所有的传参,一律全都是在拷贝复印件!
如果你发现这复印件你在函数里涂改,咋外面的也变了?
那是因为这个件印的是**“带指针锁眼的大门钥匙地址”**,拿着复印的地址你去捣腾的还是原来大马路上的那套房。
🌈 彻底阉割的指针 * 和 &
- 取地址:
&变量 - 去地址的房里拿真身值:
*指针 - ⚠️ 绝对不允许运算(如
p++),指针的唯一作用就是替值传递留一个修改实体的通道门匙。 - ⚠️ 面对未初始化的虚空指针直接
*p-> Panic!
切片、Map、Channel 不需要加
*,它三哥俩骨子里就带着原生基因“隐形指针”。
9. Interface 接口机制
在 Go,接口实现了鸭子模型的极简多态:
你只要走路像鸭子,叫声像鸭子,你就算没办证书写明
implements 鸭子,它也认你是一只钦定接口鸭!
🌈 唯一的大坑:接收者限定
如果你是用值接收者实现了方法:那么你传 狗体 或 &狗体指针 给接口对象都能兜住。
如果你是用指针接收者实现了方法:死规定,你特么只能塞且必须强行塞 &狗地址 给我才能行。
🌈 万能的空接口与破壳
所有类型不论是原始数据还是自定义奇葩类,都天生实现了 interface{} 空接口囊。
1 | var unknown interface{} = "我是个刺客" |
10. 错误捕获 (defer/err/panic)
🌈 错误提取断言
- 判断它底层根源是不是预定义常量错(Sentinel Error):
errors.Is(err, 拿来对比的预设变量) - 强行把它破壳拿里面的特定实体类型的属性错:
errors.As(err, &特定的自定错误大类型)
🌈 defer 的回旋镖(后进先出栈)
**你写的 return 语句根本就不是一劳永逸!**它有三步曲:
- 它先把值丢在后备箱变量里。
- 逆向顺藤摸走所有预先挂着的
defer。如果此刻遇到有命名返回值的大哥搞破坏影响了后备箱,你退出的答案就被改了! - 这才退出。
🌈 Panic 急救包
只把 recover() 塞进提前挂着的 defer 匿名兜底函数里才能用!
只要逮着了报错就吃进隐患,让上级功能安然无恙接着大踏步执行。
11. 终极并发 (Goroutine & Channel)
💡 通过通信来共享系统内存。
🌈 解决主死全僵的问题 (sync.WaitGroup)
放弃 time.Sleep 土鳖等协程。靠精准算术下发任务数。
- 加任务:在协程发动
go func()之前:wg.Add(1) - 退任务:切记在协程的第一行埋死兜底:
defer wg.Done() - 查结果:大主子线程结尾等收网:
wg.Wait() - ⚠️ 切记协程如果外部封装函数里带着这个计数器往下发,必定全用指针
*sync.WaitGroup传,绝不能发影子副本去糊弄。
🌈 Channel 管道交互
在不同的 Go 并行管线之间安全接抛快递件。不许在声明里画蛇添足加 * (它是自带原生引用指针体制的)。
- 强同步版
make(chan int)-> (无缓冲)双方不到齐就不准过,死锁堵塞。 - 接活版
make(chan int, 3)-> (有缓冲)放信箱不超过 3 的上限随便撒手,不用等对方拿货立马往下跑。 - 读死空结案 -> 如果使用
for range去拿货,发送端用完如果不自己发close(通道名)倒闭关门拉电闸,那收货这段就会永久处于接收痴汉傻等死机状态 (PanicDeadlock)。

