一、闭包
Go 语言支持匿名函数,可作为闭包。匿名函数是一个”内联”语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必申明。
下面一个示例,很清楚地展现了以函数为参数值的用法:
var x intinc := func() int {x++return x}fmt.Println(func() (a, b int) {return inc(), inc()}())
输出值显而易见,是 1 2,如果基础不扎实,还是不容易搞清楚的。
二、可变长度的参数
使用 ... 指定参数的长度是可变的。
var Test = func(values...int) {
for _, v := range values {
fmt.Println(v)
}
}
Test(1,2,3)
三、立即执行的函数
跟JS类似,go中也可以让函数立即执行,并且不需要像JS一样在函数之前添加 ;
func(values...int) {
for _, v := range values {
fmt.Println(v)
}
}(1,2,3)
四、返回多个值的函数
函数可以包含多个返回值:
func swap(x, y string) (string, string) {
return y, x
}
func main() {
a, b := swap("A", "B")
fmt.Println(a, b) // B A
}
五、值传递与引用传递
先看一个比较烂大街的交换数值的例子:
func swap(x int, y int) {
var temp int
temp = x
x = y
y = temp
}
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
fmt.Printf("交换前 a 的值为 : %d\n", a ) // 100
fmt.Printf("交换前 b 的值为 : %d\n", b ) // 200
/* 通过调用函数来交换值 */
swap(a, b)
fmt.Printf("交换后 a 的值 : %d\n", a ) // 100
fmt.Printf("交换后 b 的值 : %d\n", b ) // 200
}
程序中使用的是值传递,所以两个值并没有实现交换。
使用引用的示例:
func swap(x *int, y *int) {
var temp int
temp = *x
*x = *y
*y = temp
}
func main() {
/* 定义局部变量 */
var a int = 100
var b int = 200
fmt.Printf("交换前 a 的值为 : %d\n", a ) // 100
fmt.Printf("交换前 b 的值为 : %d\n", b ) // 200
/* 通过调用函数来交换值 */
swap(&a, &b)
fmt.Printf("交换后 a 的值 : %d\n", a ) // 200
fmt.Printf("交换后 b 的值 : %d\n", b ) // 100
}
由于传递的是引用,指向内存地址,所有值成功交换了。
六、延迟语句
使用 defer 关键字可以使函数中的某一条语句延迟执行,也就是在函数结束的时候才执行。
比如在读写文件时,可以将关闭文件写在前面,以防止遗忘关闭文件的操作:
func readFile(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
return ioutil.ReadAll(file)
}
defer匿名函数
当一个函数中存在多个defer语句时,可以将其放置于匿名函数中,它们携带的表达式语句的执行顺序一定是它们的出现顺序的倒序。
func main() {
fmt.Println(1)
defer func() {
fmt.Println(2)
fmt.Println(3)
}()
fmt.Println("end")
}
循环之中的defer
当defer放于循环之中,其输出值将反向输出。
func main() {
f := func(i int) int {
fmt.Printf("%d ",i)
return i * 10
}
for i := 1; i < 5; i++ {
defer fmt.Printf("%d ", f(i))
}
}
输出:
1 2 3 4 40 30 20 10
循环中defer匿名函数
当在循环中defer的是一个匿名函数,那么其输出值将会是最终循环值。
for i := 1; i < 5; i++ {
defer func() {
fmt.Print(i)
}()
}
输出:
5555
原因是defer语句携带的表达式语句中的那个匿名函数包含了对外部(确切地说,是该defer语句之外)的变量的使用。注意,等到这个匿名函数要被执行(且会被执行4次)的时候,包含该defer语句的那条for语句已经执行完毕了。此时的变量i的值已经变为了5。因此该匿名函数中的打印函数只会打印出5。
正确的用法是:把要使用的外部变量作为参数传入到匿名函数中。(玩过JS的一定都懂)
for i := 1; i < 5; i++ {
defer func(n int) {
fmt.Print(n)
}(i)
}
七、递归函数
阶乘
func Factorial(n uint64)(result uint64) {
if n > 0 {
result = n * Factorial(n-1)
return result
}
return 1
}
func main() {
var i int = 5
fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i)))
}
斐波那契数列
func fibonacci(n int) int {
if n < 2 {
return n
}
return fibonacci(n-2) + fibonacci(n-1)
}
func main() {
var i int
for i = 0; i < 10; i++ {
fmt.Printf("%d\t", fibonacci(i))
}
}
