在 Go 语言中,函数被设计为一等公民(First-Class Citizen),这意味着函数可以像其他基本数据类型(如整数、字符串)一样被声明,可以当做参数,和返回值。
函数可赋值给变量
- 实现方式:将函数直接赋值给变量,或通过匿名函数实现
go
// 定义函数类型
type Calculator func(a, b int) int
// 为 func() 创建别名
type MyFunc = func(a, b int) int
// 赋值普通函数
var add Calculator = func(a, b int) int { return a + b }
// 赋值匿名函数
square := func(x int) int { return x * x }
函数可作为参数传递和返回
- 高阶函数示例:将函数作为参数传入其他函数,实现策略模式
go
func ProcessData(data []int, operation func(int) int) []int {
result := make([]int, len(data))
for i, v := range data {
result[i] = operation(v)
}
return result
}
// 使用示例
squared := ProcessData([]int{1,2,3}, func(x int) int { return x*x })
- 闭包实现:返回一个携带外部作用域变量的函数
go
func Counter() func() int {
count := 0
return func() int {
count++
return count
}
}
// 使用示例
counter := Counter()
fmt.Println(counter()) // 1
fmt.Println(counter()) // 2
类型定义(Type Definition)
go
package main
import "fmt"
// 定义新类型 MyFunc
type MyFunc func(int) int
// 原始函数类型
func add(a int) int { return a + 1 }
func main() {
var f MyFunc = add
// 编译错误:cannot use add (type func(int) int) as type MyFunc in variable declaration
var g MyFunc = MyFunc(add) // 正确:显式类型转换
fmt.Println(g(5)) // 输出 6
}
MyFunc
是独立类型,与func(int) int
不兼容- 必须通过
MyFunc(add)
显式转换才能赋值
类型别名(Type Alias)
go
package main
import "fmt"
// 为 func() 创建别名
type MyFunc = func()
// 原始函数
func hello() { fmt.Println("Hello") }
func main() {
var f MyFunc = hello // 直接赋值,无需转换
f() // 输出 Hello
}
MyFunc
是func()
的别名,类型完全等价- 可直接赋值,类型系统自动识别
结构体方法也可当做普通函数传递
go
package main
import (
"fmt"
"strconv"
"time"
)
type Stu struct {
Name string
Age int
}
func (s *Stu) sayHi() {
fmt.Printf("hello ereryone. my name is %s ,my age is %d, \n", s.Name, s.Age)
}
type myF = func()
func clacMyf(f myF) {
b := time.Now().UnixNano() // 纳秒级时间戳
f()
e := time.Now().UnixNano()
fmt.Println("执行时间为:" + strconv.Itoa(int(e-b)) + "纳秒")
}
func main() {
p := Stu{Name: "Alice", Age: 30}
clacMyf(p.sayHi)
}
与其他语言的对比
语言 | 函数一等公民特性 | 与 Go 的差异 |
---|---|---|
JS | 支持,动态类型 | Go 为静态类型,类型安全性更高 |
Java | 需通过接口或 Lambda 实现(Java 8+) | Go 无需接口,语法更简洁 |