- 在 Go 里,函数是头等的,它可以用在整数、字符串或其它类型能用的地方:
- 将函数赋给变量
- 将函数作为参数传递给函数
- 将函数作为函数的返回类型
将函数赋给变量
- 变量 sensor 就是一个函数,而不是函数执行的结果
- 无论 sensor 的值是 fakeSensor 还是 realSensor,都可以通过 sensor() 来调用
- sensor 这个变量的类型是函数,该函数没有参数,返回一个 kelvin 类型的值。
- 换一种声明形式的话:

将函数传递给其它函数
package mainimport ( "fmt" "math/rand" "time")type kelvin float64func measureTemperature(samples int, sensor func() kelvin) { for i := 0; i < samples; i++ { k := sensor() fmt.Printf("%vº K\n", k) time.Sleep(time.Second) }}func fakeSensor() kelvin { return kelvin(rand.Intn(151) + 150)}func main() { measureTemperature(3, fakeSensor)}
声明函数类型
- 为函数声明类型有助于精简和明确调用者的代码。
- 例如:type sensor func() kelvin
- 所以:func measureTemperature(samples int, s func() kelvin)
- 可以精简为:func measureTemperature(samples int, s sensor)
闭包和匿名函数
- 匿名函数就是没有名字的函数,在 Go 里也称作函数字面值。
- 因为函数字面值需要保留外部作用域的变量引用,所以函数字面值都是闭包的。
package mainimport "fmt"type kelvin float64// sensor function typetype sensor func() kelvinfunc realSensor() kelvin { return 0}func calibrate(s sensor, offset kelvin) sensor { return func() kelvin { return s() + offset }}func main() { sensor := calibrate(realSensor, 5) fmt.Println(sensor())}
- 闭包(closure)就是由于匿名函数封闭并包围作用域中的变量而得名的。
作业题
- 修改这段程序:
- 声明一个变量,并将其用作 calibrate 函数的 offset 实参,而不是使用字面值数字 5。在此之后,即使修改变量,调用 sensor() 的结果也仍然为 5。这是因为 offset 形参接受的是实参的副本而不是引用,也就是所谓的按值传递。
- 使用 calibrate 函数和今天讲的 fakeSensor 函数以创建新的 sensor 函数,然后多次调用这个新的 sensor 函数,看看它是否每次都会调用 fakeSensor 函数并产生随机的读数。

package mainimport ( "fmt" "math/rand")type kelvin float64type sensor func() kelvinfunc fakeSensor() kelvin { return kelvin(rand.Intn(151) + 150)}func calibrate(s sensor, offset kelvin) sensor { return func() kelvin { return s() + offset }}func main() { var offset kelvin = 5 sensor := calibrate(fakeSensor, offset) for count := 0; count < 10; count++ { fmt.Println(sensor()) }}