函数是结构化编程的最小模块单元。
函数还是代码复用和测试的基本单元。
- 无须前置声明。
- 不支持命名嵌套定义(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" // 默认优化方式,允许内联
建议命名规则
驼峰命名
函数和方法的命名规则稍有些不同。方法通过选择符调用,且具备状态上下文,可使用更简短的动词命名。