Golang:闭包

2023-05-31 0 488

预计今年写作天数:25两分钟

Golang:闭包

苏州西湖

旋量群是高阶词汇一般来说单厢包涵的一类句法,Python和Go中都全力支持那个句法。

所以,到底甚么是旋量群呢?

具体来说他们从非官方表达式已经开始讲起:

非官方表达式

反之亦然Python和Go都全力支持非官方函数,以Go为例,他们看两个单纯的范例吧:

package main importfmtfunc main() { lambda := func() { fmt.Println(“Im an anonymous function”) } lambda() }

运转结论:

➜ closure git:(master) ✗ go run lambda.go Im an anonymous function

表达式做为二等国民(First class citizen),能把它赋给两个表达式,这种就能努力做到动态预览:

package main import “fmt” func main() { var functor func() int functor = func() int { return 10 } fmt.Println(functor()) functor = func() int { return 15} fmt.Println(functor()) functor =func() int { return 20 } fmt.Println(functor()) }

运转结论:

closure git:(master) go run functor_realtime_update.go 10 15 20

旋量群

如果两个内部嵌套表达式中,引用了外部定义的表达式,所以他们就称那个表达式为“旋量群”,同时他们称被引用的表达式为“引用表达式”或“自由表达式”。

下面他们看两个引用外部表达式的嵌套表达式:

package main import “fmt” func main() { var nestedFunctorInMain func()counter :=0 nestedFunctorInMain = func() { counter += 1fmt.Println(counter) } nestedFunctorInMain() nestedFunctorInMain() nestedFunctorInMain() }

运转结论:

closure git:(master) go run nested_function.go 1 2 3

这里的“nestedFunctorInMain”就是两个旋量群,它嵌套在入口表达式“main”中,并且引用了外部表达式“counter”。

那旋量群有甚么特殊的用处呢?最单纯的,利用旋量群特性,他们能达到数据隔离的目的:

package main importfmtfunc main() { counter := newCounter() fmt.Println(counter()) fmt.Println(counter()) } func newCounter() func() int { n := 0 return func() int { n += 1return n } }

运转结论:

closure git:(master)go run data_isolation.go 1 2

之前的嵌套表达式的范例里面,他们的旋量群使用了main表达式中的外部变量,但是那个表达式使用范围过大,其他表达式也能预览它,在本例中,他们设置在新表达式中设置表达式“n”,而嵌套非官方表达式引用它,即使“newCounter”表达式执行完毕,表达式依然存在旋量群中,且外部无法访问,这种就很方便地达到了数据隔离的目的。

旋量群中遇到的常见问题

defer和go使用表达式调用做为参数

假设他们有个setup和teardown的功能需要实现,即在表达式执行前利用setup做一些初始化操作,然后在执行结束后,做环境清理工作:

package main import “fmt” func main() { defer func() { fmt.Prinltn(“teardown”) } }

运转结果:

➜ closure git:(master) ✗ go run defer_need_func_call.go# command-line-arguments ./defer_need_func_call.go:3:8: imported and not used: “fmt” ./defer_need_func_call.go:8:4: expression in defermust be function call

因为“defer”和“go”关键字的参数是表达式调用,而不是表达式,所以按照本例的写法,编译代码时会报错:“expression in defer must be function call”。

他们改进一下:

package main import “fmt” func main() { defer setup() } func setup() func() { fmt.Println(“pretend to set things up”) return func() { fmt.Println(“pretend to tear things down”) } }

运转结论:

closure git:(master)go run defer_need_func_call.go pretend to set things up

“teardown”并未得到执行!为甚么?

仔细看本例中代码,“setup”表达式返回非官方表达式,即“teardown”,但是“teardown”并未有机会得到显式执行,所以代码未运转到。

再改进一下:

package main import “fmt” func main() { defer setup()() } func setup() func() { fmt.Println(“pretend to set things up”) return func(){ fmt.Println(“pretend to tear things down”) } }

运转结论:

closure git:(master)go run defer_need_func_call.go pretend to set things up pretend to tear things down

显式执行返回的非官方表达式,“teardown”部分得到执行。

“for”循环中的表达式是引用传递而非值传递

那个问题很容易让人迷惑,他们先看个范例:

package main import “fmt” func main() { var functions []func() for i := 0; i < 10; i++ { functions =append(functions, func() { fmt.Println(i) }) } for _, f := rangefunctions { f() } }

运转结论:

closure git:(master) go run for_loop_refer_assign.go 10 10 10 10 10 10 10 10 10 10

按照他们在理解,不是应该按顺序输出“0”到“9”的数字吗?这是因为,当他们在“for”循环做迭代的时候,“for”内部的表达式传递不是他们一般来说理解的值传递,而是引用传递,导致最后表达式切片中所有的表达式中使用到的表达式“i”都是循环之后表达式“i”的值,从而最后输出的都是“10”。

那如果他们想按照初衷一次打印每个迭代中的数字,如何做呢?

有一类办法能努力做到,因为表达式参数是值传递,能通过两个辅助表达式达到目的:

package main import “fmt” func main() { var functions []func() for i := 0; i < 10; i++ { functions = append(functions, build(i)) }for _, f := range functions { f() } } func build(val int) func() { return func() { fmt.Println(val) } }

运转结论:

closure git:(master) go run for_loop_refer_assign.go 0 1 2 3 4 5 6 7 8 9

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务