函数是结构化编程的最小模块单元。

函数还是代码复用和测试的基本单元。

  • 无须前置声明。
  • 不支持命名嵌套定义(nested)。
  • 不支持同名函数重载(overload)。
  • 不支持默认参数。
  • 支持不定长变参。
  • 支持多返回值。
  • 支持命名返回值。
  • 支持匿名函数和闭包。
func main() { 
	func add(x, y int) int { // 错误:syntax error:unexpected add,expecting(
		return x + y
	} 
}

和前面曾说过的一样,左花括号不能另起一行。

函数属于第一类对象,具备相同签名(参数及返回值列表)的视作同一类型。

第一类对象(first-class object)指可在运行期创建,可用作函数参数或返回值,可存入变量的实体。最常见的用法就是匿名函数。

从阅读和代码维护的角度来说,使用命名类型更加方便。

// 定义函数类型 
type FormatFunc func(string, ...interface{}) (string, error)
 
// 如不使用命名类型,这个参数签名会长到没法看 
func format(f FormatFunc, s string, a ...interface{}) (string, error) { 
	return f(s, a...)
}

函数只能判断其是否为 nil,不支持其他比较操作。

func a() {}
func b() {}
func main() {
   println(a == nil)
   println(a == b) // 无效操作:a==b(func can only be compared to nil)
}

从函数返回局部变量指针是安全的(与 rust 不同),编译器会通过逃逸分析(escape analysis)来决定是否在堆上分配内存。

func test() *int { 
	a := 0x100
	return &a
} 
  
func main() {
   var a *int = test()
   println(a, *a)
}

函数内联(inline)对内存分配有一定的影响。如果上例中允许内联,那么就会直接在栈上分配内存。

go build-gcflags"-l-m"   // 禁用函数内联,输出优化信息
go build-gcflags"-m"     // 默认优化方式,允许内联

建议命名规则

驼峰命名

函数和方法的命名规则稍有些不同。方法通过选择符调用,且具备状态上下文,可使用更简短的动词命名。