Go_Learning_2_函数式编程

Go_Learning_2_函数式编程



首先函数式编程是一种数学思想,相较于传统的命令式编程有这思想上的差异,此篇仅记录某些具体表现形式,真正的编程思想仍任重道远,希望十年后的自己能对函数式编程思想有更深入的认识

0. 函数

  1. 可以有多个返回值
  2. 所有参数都是值传递:slice,map,channel会有传引用的错觉
  3. 函数可以作为变量的值
  4. 函数可以作为参数和返回值

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进行了统一的封装

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值