函数是每门编程语言重要组成部分,golang作为一门现代化的语言,函数上有自己的一些特点
特点
1. 支持可变参数函数(variadic function)
如果一个函数的参数数量是可变的,则该函数是可变参数函数
Go中可变参数函数的最后一位参数使用 参数名 ...类型的格式声明,表明该类型参数可传入的数量是不限制的
func function_name(para1 type,para2 type, para3 ...type){
// code...
}
要点:
- 在函数内部 ...type参数是用一个slice类型的变量表示
- 可以用 slice类型变量...方式传入可变参数
package main
import "fmt"
func sum(init int,nums ...int) {
for _, num := range nums { // nums是slice 类型
init += num
}
fmt.Println(total)
}
func main() {
// 参数的数量可变
sum(0,1, 2) // 3
sum(0,1, 2, 3) // 6
nums := []int{1, 2, 3, 4}
sum(nums...) // 传入可变参数
}
2. 可以定义多个返回值并为返回值命名
函数返回多个值是开发中很常见的需求,然而大部分语言都不直接支持返回多个值,需程序员们另辟蹊径,通常解决方法是把多个值用对象或者数组包装起来,如 js 可以把多个返回值放在一个object中
function getNames() {
let firstName = 'John',
lastName = 'Doe';
return {
firstName,
lastName
};
}
Go则在语言层面直接支持了这一特性
package main
import "fmt"
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}
同时可以给返回值命名,从而使得函数更加清晰,可读性更强
func RGBA() (r, g, b, a uint32) {
.....
}
func nextInt(b []byte, pos int) (value, nextPos int) {
....
}
如果返回值已经命名,函数可以直接return不携带返回值,这种称为naked return(裸返回), naked return在较短的函数中使用可以简化代码,但一般不建议在较长的函数内使用,它会降低函数可读性
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
3. 支持一等函数(first class function)和高阶函数(high order function)
一等函数, 即把函数看成和其他变量类型一样,允许把函数赋值给一个变量,允许把函数作为其他函数的参数和返回值。
如果一个函数的参数或者返回值包含另一个函数,则该函数是高阶函数。
package main
import "fmt"
func sayHello() string {
return "hello, "
}
func greeting(sayHello func() string, name string) { // sayHello 函数被当做greeting函数的一个参数
fmt.Println(sayHello() + name)
}
func main() {
greeting(sayHello, "go") // hello, go
}
高阶函数的写法可以提高我们代码更加简洁优雅。如Go的排序函数Slice,通过传入less函数实现排序:
func Slice(slice interface{}, less func(i, j int) bool) {
rv := reflectValueOf(slice)
swap := reflectSwapper(slice)
length := rv.Len()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
}
使用:
package main
import (
"fmt"
"sort"
)
func main() {
people := []struct {
Name string
Age int
}{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}
sort.Slice(people, func(i, j int) bool { return people[i].Name < people[j].Name }) // 按照 Name排序
fmt.Println("By name:", people) // By name: [{Alice 55} {Bob 75} {Gopher 7} {Vera 24}]
sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age }) // 按照 Age 排序
fmt.Println("By age:", people) // By age: [{Gopher 7} {Vera 24} {Alice 55} {Bob 75}]
}
闭包(closure)
闭包,是由一个函数与它引用的外部变量构成,可以理解它是一个持有外部变量的特殊函数,闭包通常出现在高阶函数中
package main
import "fmt"
func intSeq() func() int {
i := 0
return func() int { // 返回函数与i构成一个闭包
i++
return i
}
}
func main() {
nextInt := intSeq()
fmt.Println(nextInt()) // 1
fmt.Println(nextInt()) // 2
fmt.Println(nextInt()) // 3
}
intSeq 函数返回一个闭包,该闭包持有i变量,在Go内部实际上是用一个结构体表示
type Closure Struct {
i *int
f func()int
}