Go函数参数必须先写名后写类型,不支持C/Java风格;多同类型参数可缩写;参数名不可省略;多返回值需全部接收或显式忽略;所有参数值传递,但slice/map/chan/*T因含指针表现类似引用;函数类型由签名严格定义。

func 关键字后面必须跟参数名再跟类型
Go 不允许像 C 或 Java 那样把类型写在参数名前面,func add(int a, int b) int 是非法的。编译器会直接报错:expected ‘)’, found ‘a’。正确写法是 func add(a int, b int) int。
多个同类型参数可以缩写:func max(a, b, c int) int 等价于分别声明每个参数类型。但一旦类型不同,就必须显式写出每个参数名和类型,比如 func format(name string, age int, active bool) string。
- 参数名不能省略(哪怕只用一次),否则无法在函数体内引用
- 如果参数名无实际用途(如仅用于占位),可用下划线
_,但不推荐滥用 - 命名参数在文档和 IDE 提示中更友好,比如
func openFile(path string, mode int) (*os.File, error)比func openFile(string, int) (*os.File, error)更易懂
多返回值必须用变量一一接收或显式忽略
调用像 os.Open 这类返回 (*os.File, error) 的函数时,不能只取第一个值:f := os.Open("x.txt") 会编译失败 —— Go 要求你明确处理所有返回值。
常见写法是用两个变量接收:f, err := os.Open("x.txt");若只关心错误,可用 _, err := os.Open("x.txt") 忽略第一个值。但顺序不能颠倒:err, f := os.Open("x.txt") 会导致类型错配(err 被赋成 *os.File 类型)。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 命名返回值(如
func split(n int) (x, y int))支持裸return,但容易漏初始化某个返回变量,导致静默返回零值 - 多个返回值类型不同时,IDE 或
go vet可能无法捕获顺序错误,靠人眼核对最稳妥 - 不要为了“简洁”而用
_, _ := someFunc(),除非你真不需要任何返回值
所有参数都是值传递,但 slice/map/chan/*T 表现像“引用”
Go 没有引用传递,只有值传递。但像 []int、map[string]int、chan int 和 *struct{} 这些类型,其值本身包含指针字段,复制后仍指向同一底层数据。
例如传一个 slice 进函数,修改其中元素会影响原 slice;但若在函数内做 s = append(s, 1) 且触发扩容,新 slice 就不会影响外部 —— 因为此时 s 指向了新底层数组,而原变量仍指向旧数组。
- 想确保修改生效,对 slice 做增删操作后,必须把新 slice 返回并重新赋值给调用方变量
- 传
*T是最明确的“可修改外部状态”方式,但要注意 nil 指针解引用会 panic - 纯值类型(
int、string、struct{})传参后修改完全不影响外部,这点和 Python 的不可变对象不同
函数是一等公民,但类型由签名严格定义
func(int, string) bool 和 func(string, int) bool 是两种完全不同类型,不能互相赋值。哪怕参数名、顺序、类型都一样,只是返回值名不同(如 (a int) vs (b int)),类型也相同;但返回值个数或类型不同,就绝不兼容。
这直接影响闭包和回调使用:比如 sort.Slice 要求传入 func(i, j int) bool,你不能传一个 func(x, y int) bool —— 即使逻辑一模一样,名字不同也不行。
- 函数变量赋值前,务必确认签名(包括参数顺序、类型、返回值个数与类型)完全一致
- 匿名函数常用于 defer、goroutine 或 map/filter 场景,但注意闭包捕获的是变量引用,不是快照 —— 循环中启动 goroutine 时尤其容易踩坑
- 跨包调用函数时,导出函数名首字母必须大写,否则其他包无法访问

















