函数是Go语言中的“一等公民”,可以像变量一样被传递、赋值和调用。Go函数支持多返回值、命名返回值、可变参数、闭包等特性,使得代码更加简洁和模块化。本章将系统讲解函数的定义、调用以及各种高级用法。
使用func关键字定义函数。语法:func 函数名(参数列表) (返回值列表) { 函数体 }。
package main
import "fmt"
// 无参数,无返回值
func sayHello() {
fmt.Println("Hello, Go!")
}
// 带参数,无返回值
func greet(name string) {
fmt.Printf("Hello, %s\n", name)
}
// 带参数,单返回值
func add(a int, b int) int {
return a + b
}
func main() {
sayHello()
greet("World")
sum := add(10, 20)
fmt.Println("Sum:", sum)
}
如果连续参数类型相同,可以省略前面参数的类型名:func add(a, b int) int。
Go中所有参数都是值传递(拷贝值)。但切片、map、通道、接口等引用类型拷贝的是指针,因此函数内修改会影响外部。
// 值类型:整数
func modifyInt(x int) {
x = 100
}
v := 10
modifyInt(v)
fmt.Println(v) // 10(原值不变)
// 引用类型:切片
func modifySlice(s []int) {
s[0] = 999
}
nums := []int{1,2,3}
modifySlice(nums)
fmt.Println(nums[0]) // 999(被修改)
// 若想修改值类型本身,需传指针
func reallyModify(x *int) {
*x = 100
}
reallyModify(&v)
fmt.Println(v) // 100
函数可以返回多个值,常用于返回结果与错误。
// 返回商和余数
func divmod(a, b int) (int, int) {
return a / b, a % b
}
// 实际使用:返回计算结果和错误信息
func safeDivide(a, b float64) (float64, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}
func main() {
q, r := divmod(10, 3)
fmt.Printf("10/3=商%d 余%d\n", q, r)
res, err := safeDivide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println(res)
}
}
可以为返回值命名,这样函数内可以直接对它们赋值,使用return(裸返回)自动返回它们。命名返回值常用于文档化和缩短代码。
// 计算矩形面积和周长,返回值命名
func rectProps(length, width float64) (area, perimeter float64) {
area = length * width
perimeter = 2 * (length + width)
return // 裸返回,自动返回 area 和 perimeter
}
func main() {
a, p := rectProps(3, 4)
fmt.Printf("面积: %.2f, 周长: %.2f\n", a, p)
}
使用...语法接受零个或多个参数,参数在函数内部表现为切片类型。
func sum(nums ...int) int {
total := 0
for _, v := range nums {
total += v
}
return total
}
func main() {
fmt.Println(sum(1,2,3)) // 6
fmt.Println(sum(10,20,30,40)) // 100
// 传入现有切片需用...解包
numbers := []int{2,4,6}
fmt.Println(sum(numbers...)) // 12
}
函数可以赋值给变量、作为参数传递、作为返回值。
// 赋值给变量
var operation func(int, int) int
operation = func(a, b int) int { return a * b }
fmt.Println(operation(3,4)) // 12
// 作为参数(回调)
func apply(arr []int, callback func(int) int) []int {
result := make([]int, len(arr))
for i, v := range arr {
result[i] = callback(v)
}
return result
}
// 作为返回值
func makeMultiplier(factor int) func(int) int {
return func(x int) int {
return x * factor
}
}
func main() {
doubled := apply([]int{1,2,3}, func(x int) int { return x*2 })
fmt.Println(doubled) // [2,4,6]
multiplyBy5 := makeMultiplier(5)
fmt.Println(multiplyBy5(7)) // 35
}
匿名函数即没有名字的函数,可以直接定义并调用,或赋值给变量。闭包是指匿名函数捕获外部变量的能力。
// 立即执行匿名函数
func() {
fmt.Println("匿名函数被调用")
}()
// 闭包:计数器
func newCounter() func() int {
count := 0
return func() int {
count++
return count
}
}
c1 := newCounter()
fmt.Println(c1()) // 1
fmt.Println(c1()) // 2
c2 := newCounter()
fmt.Println(c2()) // 1(独立计数)
Go支持函数递归调用,需注意终止条件。
func factorial(n int) int {
if n == 0 {
return 1
}
return n * factorial(n-1)
}
fmt.Println(factorial(5)) // 120
defer确保函数返回前执行特定操作(如资源释放)。多个defer按LIFO顺序执行。
func readFile(filename string) error {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close() // 保证文件最终被关闭
// 处理文件...
return nil
}
package main
import "fmt"
type FilterFunc func(int) bool
func filter(nums []int, f FilterFunc) []int {
result := make([]int, 0)
for _, v := range nums {
if f(v) {
result = append(result, v)
}
}
return result
}
func mapFunc(nums []int, f func(int) int) []int {
res := make([]int, len(nums))
for i, v := range nums {
res[i] = f(v)
}
return res
}
func main() {
data := []int{1, 2, 3, 4, 5, 6}
// 过滤偶数
evens := filter(data, func(v int) bool { return v%2 == 0 })
fmt.Println("evens:", evens)
// 将结果平方
squares := mapFunc(evens, func(v int) int { return v * v })
fmt.Println("squares:", squares)
// 链式调用(手动组合)
result := mapFunc(filter(data, func(v int) bool { return v > 3 }), func(v int) int { return v * 10 })
fmt.Println("result:", result) // [40,50,60]
}