go语法无“可选学”部分:包级变量禁用:=;map/slice需显式初始化;defer参数在注册时求值;接口实现需方法集匹配;无隐式类型转换。

Go 语法没有“可选学”部分——var 和 := 混用、map 忘记 make、defer 误写在循环里,三者任一踩中就会 panic 或静默逻辑错误。
变量声明:别让 := 在函数外出现
Go 要求包级变量必须用 var 声明,:= 只能在函数内部使用。这是编译器强制规则,不是风格建议。
-
:=是短变量声明,会自动推导类型并完成定义;包级作用域不支持这种语法,否则报错non-declaration statement outside function body - 全局变量若需初始化,写成
var name string = "go"或更简洁的var name = "go"(类型由右值推导) - 多个包级变量建议用括号分组,避免重复写
var:var ( port = 8080 debug = true version = "v1.2.0" )
map 和 slice 初始化:零值 ≠ 可用值
map 和 slice 的零值都是 nil,但直接赋值会 panic。它们必须显式初始化才能写入。
-
map必须用make(map[string]int)或字面量map[string]int{"a": 1};直接var m map[string]int; m["k"] = 1触发panic: assignment to entry in nil map -
slice零值是nil,但append可安全作用于nilslice(会自动分配底层数组),所以var s []int; s = append(s, 1)是合法的 - 若需预分配容量,用
make([]int, 0, 10);注意第二个参数是长度(len),第三个是容量(cap),别反了
defer 执行顺序和参数求值时机常被误解
defer 不是“函数退出时才执行”,而是“语句执行时注册,函数返回前倒序执行”,且**参数在 defer 语句出现时就求值**。
- 下面代码输出
0而非2:i := 0 defer fmt.Println(i) // i 此刻是 0 i = 2
- 想捕获变化后的值?传函数闭包:
i := 0 defer func() { fmt.Println(i) }() // i 在闭包内读取,输出 2 i = 2 - 在循环中直接写
defer f(i)很危险——所有 defer 都会拿到循环终值;应写成defer func(v int) { f(v) }(i)
接口实现:不是“实现了方法就行”,而是“方法集匹配”
结构体指针接收者方法,只有该指针类型才满足接口;值接收者方法,值和指针都满足。这点直接影响能否赋值给接口变量。
- 定义
func (s *MyStruct) Close() error,那么只有*MyStruct类型能赋给io.Closer接口,MyStruct{}直接赋值会编译失败 - 标准库如
os.File的方法基本都是指针接收者,所以os.Open()返回的是*os.File,不是os.File - 空接口
interface{}确实能装任何值,但类型断言时仍要匹配底层具体类型,比如v.(string)对整数会 panic
最易被忽略的是:Go 中没有隐式类型转换,int 和 int64 是完全不同的类型,函数参数或 map key 类型不匹配时不会自动转,编译直接报错——这不是运行时问题,没法靠测试覆盖,只能写代码时盯紧类型签名。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











