目录
一、函数是一等功公民
1、与其它主要编程语言的差异
- 可以有多个返回值;
- 所有参数都是值传递,slice、 map、channel 会有传引用的错觉;
- 函数可以作为变量的值;
- 函数可以作为参数和返回值。
2、slice、 map、channel 会有传引用的错觉
当我们把 slice、 map、channel 传过去后,修改了里面的值,外面也能感受到,这就让我们感觉传递的是引用而不是值,那是因为像切片它本身只是一个数据结构,这个数据结构里面包含了指向一段儿连续存储空间的指针,所以说即便是在传值的情况下,它的值被复制到其它函数里了,当我们去修改切片的某个值时,其实操作的是同一块儿存储空间,所以就有一种传引用的错觉。
3、为什么函数在 Go 语言里面是一等公民
函数可以作为变量的值,作为参数和返回值可以很大程度的简化我们的程序并创造一些十分友好的使用方式。
4、函数可以有多个返回值
package _func
import (
"math/rand"
"testing"
)
func TestFun(t *testing.T) {
number1, number2 := returnMultiValues()
t.Log(number1, number2) //31 87
}
//函数有多个返回值
//花括号的前面用小括号定义好返回值的类型
func returnMultiValues() (int, int) {
return rand.Intn(50), rand.Intn(100)
}
5、函数作为参数值和返回值
package _func
import (
"fmt"
"testing"
"time"
)
//计算函数的花费时长,将函数作为参数,函数作为返回值
//这个函数有点像装饰器模式,就是在运行函数的前后加上了计时功能
func timeSpend(inner func(op int) int) func(op int) int {
return func(op int) int {
//开始时间
start := time.Now()
//运行这个函数
ret := inner(op)
//打印函数的运行时长
fmt.Println("time spend:", time.Since(start).Seconds())
//返回值仍然是个函数
return ret
}
}
//这是一个慢函数
func slowFunc(op int) int {
//sleep两秒
time.Sleep(time.Second * 2)
return op * op
}
func TestFun(t *testing.T) {
//将函数传给 timeSpend() 函数作为参数,返回值是具有即时功能的一个函数
timeSpendSlowFunc := timeSpend(slowFunc)
//运行这个具有计时功能的函数
slowFuncRes := timeSpendSlowFunc(10)
t.Log(slowFuncRes)
//执行结果:
//time spend: 2.001692741
//func_test.go:51: 100
}
6、自定义类型
通过自定义类型,很多比较长的参数可以被大大简化,让我们的程序更加简洁可读。例如上面的timeSpend() 函数,它的参数也是一个函数,看起来比较长,我们可以通过自定义类型来简化。
package custom_type
import (
"fmt"
"testing"
"time"
)
//timeSpend()的参数是一个方法,方法太长,不利于阅读,我们可以自定义类型,
//我们也可以把它理解为一个别名
type IntConversionFun func(op int) int
//通过自定义类型,timeSpend() 的参数就被大大简化了,让我们的程序更加简洁可读
func timeSpend(inner IntConversionFun) IntConversionFun {
return func(op int) int {
//开始时间
start := time.Now()
//运行这个函数
ret := inner(op)
//打印函数的运行时长
fmt.Println("time spend:", time.Since(start).Seconds())
//返回值仍然是个函数
return ret
}
}
//这是一个慢函数
func slowFunc(op int) int {
//sleep两秒
time.Sleep(time.Second * 2)
return op * op
}
func TestFun(t *testing.T) {
//将函数传给 timeSpend() 函数作为参数,返回值是具有即时功能的一个函数
timeSpendSlowFunc := timeSpend(slowFunc)
//运行这个具有计时功能的函数
slowFuncRes := timeSpendSlowFunc(10)
t.Log(slowFuncRes)
//执行结果:
//time spend: 2.001692741
//func_test.go:51: 100
}
二、可变长参数
1、求和函数
package _func
import (
"testing"
)
//可变长参数,求和
//用三个点儿代表多个参数
func Sum(opts ...int) int {
sum := 0
for _, op :=range opts {
sum += op
}
return sum
}
func TestVarParams(t *testing.T) {
total := Sum(1, 2, 3, 4)
t.Log(total)
}
三、defer 延迟执行函数
package _func
import (
"fmt"
"testing"
)
//清理释放资源
func clearResources(){
fmt.Println("This func will clear resources.")
}
//defer 延迟执行函数
func TestDefer(t *testing.T) {
//defer 后面的函数将会在其它语句都执行完毕后,在 return 之前才会执行。
//利用这个特性,我们可以用来在函数运行完毕后释放资源。
defer clearResources()
//当有多个 defer 函数是,后面的 defer 函数会比前面的 defer 函数先执行
defer func() {
t.Log("Another defer func. ")
}()
t.Log("This code's position is after defer, but it will run before defer")
//panic 用来抛出 Go 语言无法修复的错误。
//即便是抛出了 panic 错误,defer 依旧会执行
panic("Fatal err")
//panic 后面的代码将不会被执行,还会报 Unreachable 的提示
t.Log("This code is after panic, it will not be run")
}
注:这篇博文是我学习中的总结,如有转载请注明出处:
https://blog.csdn.net/DaiChuanrong/article/details/118047179
上一篇:Go字符串
下一篇:Go面向对象-行为的定义和实现