函数是基本的代码块,用于执行一个任务。Go 语言最少有个 main() 函数。你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务。函数声明告诉了编译器函数的名称,返回类型,和参数。Go 语言标准库提供了多种可动用的内置的函数。例如,len() 函数可以接受不同类型参数并返回该类型的长度。如果我们传入的是字符串则返回字符串的长度,如果传入的是数字,则返回数组中包含的函数个数。
自定义函数
package main
import (
"fmt"
)
//值拷贝(值传递)、地址拷贝(地址传递)
func main() {
a := 1
myfun(a)
fmt.Println("main里输出,这是值传递", a)
}
func myfun(a int) {
a = 2//值传递不会改变原来的值
fmt.Println("myfun里输出,这是值传递", a)
}
输出:
myfun里输出,这是值传递 2
main里输出,这是值传递 1
package main
import (
"fmt"
)
//值拷贝(值传递)、地址拷贝(地址传递)
func main() {
a := 1
myfun(&a)
fmt.Println("main里输出,这是地址传递", a)
}
func myfun(a *int) {
*a = 2 //地址传递会改变原来的值
fmt.Println("myfun里输出,这是地址传递", *a)
}
myfun里输出,这是地址传递 2
main里输出,这是地址传递 2
package main
import (
"fmt"
)
func main() {
a := A //a变成了函数类型
a()
}
func A() {
fmt.Println("函数类型")
}
输出:
函数类型
匿名函数
package main
import (
"fmt"
)
func main() {
a := func() {
fmt.Println("匿名函数")
}
a()
}
匿名函数
闭包
package main
import (
"fmt"
)
func main() {
f := closure(10)
fmt.Println(f(1))
fmt.Println(f(2))
}
//闭包可以使局部变量递增
//因为打印出的3次x的地址都是一样的,所以他们指向同一个x地址,不是值得拷贝,而是指向x的原始地址
func closure(x int) func(y int) int {
fmt.Printf("%p\n", &x)
return func(y int) int {
fmt.Printf("%p\n", &x)
return x + y
}
}
输出:
0xc042048080
0xc042048080
11
0xc042048080
12
不定长传参
package main
import (
"fmt"
)
func main() {
A("GO", 1, 2, 3, 4, 5, 6, 7, 8, 9)
}
//不定长变参,注意的是当有多种类型的参数时,不定长参数应该写在最后面
func A(s string, a ...int) {
//其实a就是一个slice
fmt.Println(s, a)
}
GO [1 2 3 4 5 6 7 8 9]
defer的使用(GO里的“析构函数“)
package main
import (
"fmt"
)
func main() {
fmt.Println("a")
//注意的是:函数体执行结束后按照调用顺序的相反顺序逐个执行,所以先输出c,再输出b
defer fmt.Println("b")
defer fmt.Println("c")
}
a
c
b
package main
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ {
defer fmt.Println(i)//i作为参数传入,则就是当前循环时i值的拷贝,由于defer是倒序执行的,即从4开始,一直到0
}
}
输出:
4
3
2
1
0
有匿名函数,即使用闭包
import (
"fmt"
)
func main() {
for i := 0; i < 5; i++ {
//如果函数体内某个变量作为defer时匿名函数的参数,则在定义defer时即已经获得了拷贝,否则则是引用某个变量的地址
//为什么5次输出都是5?
//因为i一直都是作为引用,作为局部变量i,而上个例子则是作为参数传进去,所以运行到defer时就对i的值进行了拷贝,所以会输出4,3,2,1,0,而现在这个i是作为地址的引用,引用了局部变量,所以退出for循环体的时候就变成了5,而在这个匿名函数return的时候,就开始执行defer语句,那这时defer就是引用i等于3的情况,因为for循环了5次,类似于for里有5个defer表达式,那么就会打印出5个5,这个就是defer与匿名函数、以及在闭包里使用注意的地方。
defer func() {
fmt.Println(i)
}()
}
}
输出:
5
5
5
5
5