go函数语法严格:func关键字、参数名在类型前、返回值类型固定位置;多返回值须括号包裹;命名返回值在defer中可见;不支持具名嵌套函数;传指针避免大结构体拷贝;接口调用指针方法时底层值必须可寻址。

Go 语言里函数不是“怎么声明更优雅”的问题,而是不按规则写就直接编译失败——func 关键字、参数类型在后、返回值位置固定,没有商量余地。
函数定义必须把类型写在参数名后面
和其他主流语言相反,Go 要求形参和返回值的类型都放在变量名之后,不是之前。写成 func add(a int, b int) int 是对的;写成 func add(int a, int b) int 会报错 expected '(', found 'a'。
常见错误场景:
- 从 Java/C++ 切过来的人习惯性把类型放前面,结果卡在语法错误上
- IDE 自动补全有时会按其他语言逻辑提示,不能盲信
- 多个同类型参数不能简写为
a, b int以外的形式(比如a int, b int可以,int a, b不行)
多返回值必须用括号包裹,哪怕只有一个
返回单个值时,括号可省略:func version() string;但只要有两个或以上,就必须写成 func split(s string) (string, string)。漏掉外层括号会触发 missing return at end of function 这类误导性错误。
实操建议:
- 即使当前只返回一个值,如果后续可能扩展,一开始就写
()括号,避免调用侧代码要跟着改 - 命名返回值(如
func count(s string) (n int))能让代码更清晰,但也容易引发“忘记 return”问题——因为编译器允许你直接写n = 5而不显式return - 命名返回值在 defer 中可见,这点常被忽略,导致 defer 里读到的是零值而非最终赋的值
函数是一等公民,但不能嵌套声明(只能嵌套定义)
Go 支持闭包,也允许在函数内部写匿名函数并赋给变量,例如:fn := func(x int) int { return x * 2 };但不允许写 func inner() {} 这样的具名嵌套函数。
为什么这样设计?
- 简化作用域规则:所有函数都在包级作用域,查找路径明确
- 避免递归调用时出现未声明错误(比如
inner()在定义前就被调用) - 真需要局部行为封装,用匿名函数 + 变量绑定更安全,也更符合 Go 的显式风格
调用时传指针还是值,直接影响性能和语义
Go 默认按值传递,结构体大了就会拷贝整块内存。比如传入一个 1KB 的 struct,每次调用都复制一次,开销明显。这时候得主动用 &v 传指针,接收方也得声明为 *MyStruct。
容易踩的坑:
- 方法接收者用了指针
func (p *Person) setName(n string),但调用时传的是值person.setName("x"),Go 会自动取地址——前提是person是可寻址的(不能是字面量或 map 中的直取值) -
map[string]Person中取出来的Person值不可寻址,此时m["k"].setName("x")会编译失败 - 接口类型变量调用指针方法时,底层值必须是指针,否则 panic:“call of pointer method on … not addressable”
函数签名里的每个位置都有强制语义,少一个括号、错一个顺序、漏一个星号,编译器就不会让步。最麻烦的往往不是不会写,而是改了一处,忘了同步更新调用方或接口实现——尤其在多人协作时,这类错误藏得深,运行期才暴露。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











