Go 语言函数

多返回值、命名返回、可变参数、闭包、defer、方法。

Beginner
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
15

Inside 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 3

defer

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
1
defer 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
2

A 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.

Friends & Partners