Go 中的函数基本可分为普通函数、匿名函数和方法,方法可视为绑定在结构体上的函数,将在之后单独讲解

普通函数的声明

函数声明包括函数名,参数(入参,形参,随你怎么叫)列表,返回值(出参)列表以及函数体

1
2
3
func 函数名([入参列表]) [返回值列表] {
函数体
}

函数返回值

一个函数可以有返回值,也可以没有返回值,甚至可以有多个返回值

下面是一个简单的函数

1
2
3
func sum(a, b int) int {
return a + b
}

你可以在返回值列表就把返回的变量给定义好,这样可以 return 的时候会自动返回对应的变量

1
2
3
4
func sum(a, b int) (c int) { // 这种写法以及多返回值都要加括号
c = a + b
return
}

多返回值的例子

1
2
3
func divi(a, b int) (int, int) {
return a / b, a % b
}

函数参数

值传递还是引用传递

在 C++ 中,函数一般是值传递,也就是传递的是实参的拷贝,在函数中修改形参不会影响实参

在 Go 中也是如此,基本类型是值传递,但引用类型(如指针,slice、map、function、channel 等类型)传过去的可以看作是指针,实参会因为引用关系而修改

也就是说,基本类型是值传递,引用类型可以看作引用传递

可变参数

Go 的可变参数是在 [C/C++ 的版本](C/C++ 的版本) 上改进的,它解决了一些痛点,让使用更加方便

还是经典的求和函数,因为使用了可变参数,它可以接受任意个 int 类型的参数

1
2
3
4
5
6
7
func sum(vals ...int) int {
total := 0
for _, val := range vals {
total += val
}
return total
}

在函数体中,vals 可以被看作是 int 类型的切片

1
2
3
fmt.Println(sum())           // "0"
fmt.Println(sum(3)) // "3"
fmt.Println(sum(1, 2, 3, 4)) // "10"

但在外部,该函数的参数( ...int )不能认为是一个 int 类型的切片

1
2
3
4
func f(...int) {}
func g([]int) {}
fmt.Printf("%T\n", f) // "func(...int)"
fmt.Printf("%T\n", g) // "func([]int)"

那现在我想传入一个切片怎么办?可以使用下面的方式将切片拆成参数

1
2
values := []int{1, 2, 3, 4}
fmt.Println(sum(values...)) // "10"