Go 语言函数
多返回值、命名返回、可变参数、闭包、defer、方法。
Key PointsGo 的函数可以返回多个值,这让「结果 + 错误」成为自然的返回值组合。
定义与调用
Go
func add(a, b int) int {
return a + b
}
// 同类型参数可合并写
func swap(a, b string) (string, string) {
return b, a
}
fmt.Println(add(1, 2))
x, y := swap("a", "b")
fmt.Println(x, y)Output
3
b a命名返回值
Go
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = errors.New("除数为零")
return // 裸 return,返回当前命名值
}
result = a / b
return
}
r, err := divide(10, 2)
fmt.Println(r, err)Output
5 <nil>Named results mainly document meaning and let defer modify them. In functions longer than ~20 lines, bare return hides where values come from — write return result, err explicitly.
可变参数
Go
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
fmt.Println(sum())
fmt.Println(sum(1, 2, 3))
// 把切片展开传进去
s := []int{4, 5, 6}
fmt.Println(sum(s...))Output
0
6
15Inside the function nums is []int. So sum(s...) spreads the elements while sum(s) fails to compile on a type mismatch.
函数是一等公民
Go
// 函数类型
type Op func(int, int) int
func apply(a, b int, op Op) int { return op(a, b) }
fmt.Println(apply(3, 4, func(x, y int) int { return x * y }))
// 返回函数(闭包)
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
c := counter()
fmt.Println(c(), c(), c())Output
12
1 2 3defer
Go
func readFile(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close() // 函数返回前执行,即使中途 panic
data := make([]byte, 10)
_, err = f.Read(data)
return err
}Go
// 多个 defer 是栈:后进先出
func order() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
}
order()Output
3
2
1defer arguments are evaluated at declaration time, not execution: defer fmt.Println(i) prints the value i had then. Use a closure defer func(){ fmt.Println(i) }() for the final value.方法
Go
type Counter struct{ n int }
// 值接收者:操作副本
func (c Counter) Get() int { return c.n }
// 指针接收者:能改原值
func (c *Counter) Inc() { c.n++ }
c := &Counter{}
c.Inc()
c.Inc()
fmt.Println(c.Get())Output
2A method is a function with a receiver. Rule of thumb: use a pointer receiver to mutate state or for large structs; a value receiver for small read-only ones. Do not mix both on one type.
定义与调用
Go
func add(a, b int) int {
return a + b
}
// 同类型参数可合并写
func swap(a, b string) (string, string) {
return b, a
}
fmt.Println(add(1, 2))
x, y := swap("a", "b")
fmt.Println(x, y)Output
3
b a命名返回值
Go
func divide(a, b float64) (result float64, err error) {
if b == 0 {
err = errors.New("除数为零")
return // 裸 return,返回当前命名值
}
result = a / b
return
}
r, err := divide(10, 2)
fmt.Println(r, err)Output
5 <nil>命名返回值主要用于「文档化返回含义」和「defer 里能改返回值」。函数体超过 20 行时,裸 return 会让读者找不到返回值在哪,此时应显式写 return result, err。
可变参数
Go
func sum(nums ...int) int {
total := 0
for _, n := range nums {
total += n
}
return total
}
fmt.Println(sum())
fmt.Println(sum(1, 2, 3))
// 把切片展开传进去
s := []int{4, 5, 6}
fmt.Println(sum(s...))Output
0
6
15nums 在函数内部是 []int。所以 sum(s...) 和 sum(s) 的区别是:前者把切片元素逐个传,后者会编译报错(类型不匹配)。
函数是一等公民
Go
// 函数类型
type Op func(int, int) int
func apply(a, b int, op Op) int { return op(a, b) }
fmt.Println(apply(3, 4, func(x, y int) int { return x * y }))
// 返回函数(闭包)
func counter() func() int {
n := 0
return func() int {
n++
return n
}
}
c := counter()
fmt.Println(c(), c(), c())Output
12
1 2 3defer
Go
func readFile(name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close() // 函数返回前执行,即使中途 panic
data := make([]byte, 10)
_, err = f.Read(data)
return err
}Go
// 多个 defer 是栈:后进先出
func order() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
}
order()Output
3
2
1defer 的参数在声明时求值,不是执行时:defer fmt.Println(i) 打印的是当时的 i。想打印最终值要用闭包 defer func(){ fmt.Println(i) }()。方法
Go
type Counter struct{ n int }
// 值接收者:操作副本
func (c Counter) Get() int { return c.n }
// 指针接收者:能改原值
func (c *Counter) Inc() { c.n++ }
c := &Counter{}
c.Inc()
c.Inc()
fmt.Println(c.Get())Output
2方法就是「带接收者的函数」。规则很简单:要修改状态、或结构体较大时用指针接收者;只读且结构体小(几个字段)可用值接收者。同一个类型不要混用两种。