如何在Golang中定义函数_Golang函数声明与参数返回规则

Go函数声明必须显式标注所有参数和返回类型,不支持类型推导;变参仅能有一个且须为最后一个;函数是一等公民,但闭包捕获变量引用而非值。

函数声明必须显式写出所有参数类型和返回类型

Go 不支持类型推导或默认参数,每个参数和返回值的类型都得写清楚,不能省略。比如 func add(a, b int) int 是合法的,但 func add(a, b) intfunc add(a, b int)(无返回类型)会直接报错 missing returnexpected type

  • 多个同类型参数可简写为 func f(a, b, c string) bool,但不能跨类型混写
  • 如果函数不返回任何值,返回类型部分必须写成 func f() {},不能省略括号后的部分
  • 返回多个值时,类型列表必须用括号包裹:func split(n int) (int, int)

命名返回值会让代码更清晰,但要小心“零值陷阱”

你可以给返回值起名字,比如 func divide(a, b float64) (result float64, err error)。这样函数体内可以直接对 resulterr 赋值,且在 return 语句不带参数时,会自动返回这些变量的当前值(即“裸返回”)。

  • 裸返回只在有命名返回值时才有效,否则 return 必须带值
  • 命名返回值在函数入口处就被初始化为对应类型的零值(0""nil),如果忘了赋值,可能意外返回零值而不报错
  • 在 defer 中访问命名返回值能看到其被修改前/后的值,这点常被用于日志或错误包装

变参函数只能有一个,且必须是最后一个参数

Go 用 ... 表示变参,例如 func sum(nums ...int) int。它本质是把参数转成一个切片,所以调用时可以传 sum(1, 2, 3),也可以传 sum(nums...)(注意末尾的 ... 展开语法)。

  • ... 前的类型不能省略,且该参数必须位于参数列表最右端
  • 不能定义像 func f(x ...int, y string) 这样的函数,编译直接失败
  • 变参参数在函数内就是普通切片,可用 len()range 等操作;但无法直接将数组传入,除非显式转成切片或用 ... 展开

函数是一等公民,但闭包捕获的是变量引用而非快照

Go 支持把函数赋值给变量、作为参数传递、从函数返回,例如 var f func(int) int = func(x int) int { return x * 2 }。但要注意:循环中创建的闭包共享外部变量的引用。

for i := 0; i < 3; i++ {
    defer func() {
        fmt.Println(i) // 全部输出 3,不是 0/1/2
    }()
}
  • 常见修复方式是把循环变量作为参数传入匿名函数:defer func(v int) { fmt.Println(v) }(i)
  • 函数值比较时,只有 nil 函数能相互比较相等,两个非 nil 函数值永远不等(即使逻辑相同)
  • 方法表达式(如 T.M)和方法值(如 t.M)行为不同:前者需要显式传接收者,后者已绑定

函数签名里每个位置的类型都不能含

糊,命名返回值看着方便,实际调试时容易因零值掩盖逻辑遗漏;变参看着灵活,但展开和接收的写法稍有不慎就 panic;闭包看似简单,但在循环和 goroutine 里最容易掉进引用陷阱。