Go语言的函数,很像JavaScript语言的函数
func 函数名称 (形参1, 形参2) (返回值类型列表) {
函数体
retrun 返回值列表
}
函数的声明
函数的命名
重载:不支持
// 以下代码会报错
// 编译器会认为下面的两个方法定义是重复的
func test() {}
func test(a string) {}
无参函数
有参函数:参数类型一致
func test(x, y float32) {}
有参函数:类型不一致
func test(x string, y int) {}
有参函数:可变参数
func test(names...int) {
// 可变参数在方法内会被转换为切片,可以对切片进行遍历取值
}
无返回值函数
如果是无返回函数,返回值类型不填
func test() {
}
// 调用函数
test()
单返回值函数
如果只有一个返回值,可以省略括号
func test() string {
return "hello"
}
// 调用函数
var s = test()
多返回值函数
函数可以有多个返回值,多个返回值返回使用逗号隔开
func test() (string, int) {
return "hello", 20
}
// 调用函数
var s, i = test()
带有变量名的返回值
func namedRetValues() (a, b int) {
a = 1
b = 2
return
}
// 直接返回a 和 b
函数的调用
调用多返回值函数
忽略多返回值函数返回值
// 调用函数,忽略部分返回值
var s, _ = test()
函数参数的值传递与引用传递
基本类型形参是值传递
// 交换两个数字
func exchangeNum(num1 int, num2 int) {
var t int
t = num1
num1 = num2
num2 = t
}
func main() {
var i = 10
var j = 20
exchangeNum(i, j)
fmt.Printf("i = %d, j = %d", i, j) // 结果为 i = 10, j = 20
}
使用指针可以做到引用传递:
// 交换两个数字
// 参数类型为指针
func exchangeNum(num1Ptr *int, num2Ptr *int) {
var t int
t = *num1Ptr
*num1Ptr = *num2Ptr
*num2Ptr = t
}
func main() {
var i = 10
var j = 20
exchangeNum(&i, &j)
fmt.Printf("i = %d, j = %d", i, j) // 结果为 i = 20, j = 10
}
引用类型形参是引用传递
等数据类型。
匿名函数
定义并直接调用匿名函数
func(data int) {
fmt.Println("hello", data)
}(100)
变量函数
// 将匿名函数体保存到f()中
f := func(data int) {
fmt.Println("hello", data)
}
// 使用f()调用
f(100)
变量函数传递
package main
import (
"fmt"
)
// 遍历切片的每个元素, 通过给定函数进行元素访问
func visit(list []int, f func(int)) {
for _, v := range list {
f(v)
}
}
func main() {
// 使用匿名函数打印切片内容
visit([]int{1, 2, 3, 4}, func(v int) {
fmt.Println(v)
})
}
匿名函数应用技巧
func main() {
var skill = map[string]func(){
"fire": func() {
fmt.Println("chicken fire")
},
"run": func() {
fmt.Println("soldier run")
},
"fly": func() {
fmt.Println("angel fly")
},
}
skill["fire"]()
}
闭包(Closure)
闭包就是能够读取其他函数内部变量的函数,在其他语言中,也称为Lambda表达式。在Golang中,闭包组成如下:
下面是一个闭包累加器:
package main
import "fmt"
// 定义一个名为getSum的函数,无参,返回值是一个func (int) int 的函数
func getSum() func (int) int {
var sum = 0
return func(num int) int { // 这个拥有sum变量的匿名函数就是闭包
sum = sum + num // sum变量的作用域被扩大,将会被一直保存在内存中,所以要适当使用闭包
fmt.Println(sum)
return sum
}
}
func main() {
sumF := getSum()
sumF(1) // 1. 入门
sumF(2) // 3
sumF(3) // 6
}
结果:
defer 延迟执行语句
类似于Java的Finally语句,通常用于标记关闭资源的语句,让其使用完毕后自动关闭:
package main
import (
"fmt"
)
func main() {
testDefer()
}
func printReturn() int {
fmt.Println("defer return")
return 0
}
func testDefer() int {
fmt.Println("defer begin")
var num1 int = 30
var num2 int = 60
// 将defer放入延迟调用栈,这是一个新的栈空间
// 涉及的变量如果是基本类型,则会进行值传递,如果是引用类型则是传递引用
// 因为num1和num2是基本类型,所以打印30和60
defer fmt.Println(num1) // 先放入的是栈底,最后调用
defer fmt.Println(num2) // 后放入的是栈顶,最先调用
num1 += 10
num2 += 10
fmt.Println("num1 和 num2:", num1, num2)
return printReturn() // defer 在return语句之后运行
}
执行结果如下:
$ go run main.go
defer begin
num1 和 num2: 40 70
defer return
60
30