Go_Learning_2_函数式编程
首先函数式编程是一种数学思想,相较于传统的命令式编程有这思想上的差异,此篇仅记录某些具体表现形式,真正的编程思想仍任重道远,希望十年后的自己能对函数式编程思想有更深入的认识
0. 函数
- 可以有多个返回值
- 所有参数都是值传递:slice,map,channel会有传引用的错觉
- 函数可以作为变量的值
- 函数可以作为参数和返回值
slice之所以会被误认为是地址传递,因为slice是一个结构体,里面有一个指向数据存放地址的指针,当slice被复制后,这个指针也被复制,也通向指向了原先的那块内存,所以本质上还是值传递
多返回值
func returnMultiValues() (int, int) {
rand.Seed(time.Now().Unix()) // 重置随机数种子,否则不会变,是伪随机数
return rand.Intn(10), rand.Intn(20)
}
func TestFun(t *testing.T) {
value1, value2 := returnMultiValues()
t.Log(value1, value2)
}
案例:测试某个函数执行的时间,来测试性能
func timeSpend(inner func(op int) int) func(op int) int {
return func(n int) int {
start := time.Now()
ret := inner(n)
fmt.Println("time spent:", time.Since(start).Seconds())
return ret
}
}
func slowFun(op int) int {
time.Sleep(time.Second * 1)
return op
}
func TestFun(t *testing.T) {
spend := timeSpend(slowFun)
t.Log(spend(10))
}
--------------------------------
=== RUN TestFun
time spent: 1.0045038
func_test.go:37: 10
--- PASS: TestFun (1.01s)
PASS
1. 可变参数
多个参数存放在数组中
func Sum(ops ...int) int {
ret := 0
for _, op := range ops {
ret += op
}
return ret
}
func TestSum(t *testing.T) {
t.Log(Sum(1, 3, 4))
t.Log(Sum(1, 2, 3, 5, 6))
}
------------------------
=== RUN TestSum
func_test.go:50: 8
func_test.go:51: 17
--- PASS: TestSum (0.00s)
PASS
2. defer函数
延迟返回,类似Java的tay-finally中的finally,常用于清理资源或者释放某些锁
即使是在panic()执行之后也会执行defer后的函数
-
defer关键字允许我们推迟到函数返回值之前(或任意位置执行return语句之后)一刻才执行某个语句或函数,注意是return之后才执行defer函数,因为return同样可以包含一些操作
-
defer函数的调用会压入栈中,当外层函数返回时,被推迟的函数会按照后进先出的顺序调用
defer,return,返回值三者顺序
return献给返回值赋值,接着defer开始执行一些收尾工作,最后RET指令携带返回值退出函数
panic()是出现了严重的错误,程序被强行终止
// 这里演示具名函数
func Clear() {
fmt.Println("Clear resources.")
}
func TestDefer(t *testing.T) {
defer Clear()
fmt.Println("Start")
panic("err") // defer仍会执行
}
-------------------
=== RUN TestDefer
Start
Clear resources.
--- FAIL: TestDefer (0.00s)
panic: err [recovered]
panic: err
goroutine 35 [running]:
testing.tRunner.func1.2({0xef1cc0, 0xf3cd78})
C:/Program Files/Go/src/testing/testing.go:1209 +0x24e
....
同样也可以匿名函数
func TestDefer2(t *testing.T) {
defer func() {
t.Log("Clear resources!!")
}()
t.Log("Start")
}
但是具名函数和匿名函数是有区别的
defer的延迟执行只是最后一层调用的延迟
func outerClear(s string) {
fmt.Println("OutClear resources.")
}
func innerClear() string {
fmt.Println("innerClear")
return "abc!!!!!!"
}
func TestDefer(t *testing.T) {
defer outerClear(innerClear())
fmt.Println("Start")
}
-----------------------------
=== RUN TestDefer
innerClear
Start
OutClear resources.
--- PASS: TestDefer (0.00s)
PASS
观察先运行了defer函数中的innerClear然后是Start最后运行OutClear
再来看看匿名调用
func TestDefer2(t *testing.T) {
defer func() {
outerClear(innerClear())
}()
t.Log("Start")
}
-----------------------
=== RUN TestDefer2
func_test.go:72: Start
innerClear
OutClear resources.
--- PASS: TestDefer2 (0.00s)
PASS
这就相当于是将inner和out进行了统一的封装