• 欢迎访问周知博客,每周记录新知识
  • 祝各位学得开心!!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏吧

go语言问题(闭包)

go问题集 admin 3个月前 (02-19) 76次浏览 0个评论

通常,JS 面试,闭包应该是必考的题目。随着越来越多的语言对函数式范式的支持,闭包问题经常出现。在 Go 语言中也是如此。

这是 Go 语言爱好者周刊第 90 期的一道题目。以下代码输出什么?

package main

import "fmt"

func app() func(string) string {
	t := "Hi"
	c := func(b string) string {
		t = t + " " + b
		return t
	}
	return c
}

func main() {
	a := app()
	b := app()
	a("go")
	fmt.Println(b("All"))
}

A:Hi All;B:Hi go All;C:Hi;D:go All

这道题目答对的人蛮多的:60%。不管你是答对还是答错,如果最后再加一行代码:fmt.Println(a(“All”)),它输出什么?想看看你是不是蒙对了。(提示:你可以输出 t 的地址,看看是什么情况。)

答案:
A:Hi All; a b 是两个不同实例吧?
fmt.Println(a(“All”)) –> hi go all

解析:
01 什么是闭包
维基百科对闭包的定义:

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是在支持头等函数的编程语言中实现词法绑定的一种技术。闭包在实现上是一个结构体,它存储了一个函数(通常是其入口地址)和一个关联的环境(相当于一个符号查找表)。环境里是若干对符号和值的对应关系,它既要包括约束变量(该函数内部绑定的符号),也要包括自由变量(在函数外部定义但在函数内被引用),有些函数也可能没有自由变量。闭包跟函数最大的不同在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即便脱离了捕捉时的上下文,它也能照常运行。捕捉时对于值的处理可以是值拷贝,也可以是名称引用,这通常由语言设计者决定,也可能由用户自行指定(如 C++)。

关于(函数)闭包,有几个关键点:
1.函数是一等公民;
2.闭包所处环境,可以引用环境里的值;

问到什么是闭包时,网上一般这么回答的:

在支持函数是一等公民的语言中,一个函数的返回值是另一个函数,被返回的函数可以访问父函数内的变量,当这个被返回的函数在外部执行时,就产生了闭包。

所以,上面题目中,函数 app 的返回值是另一个函数,因此产生了闭包。

02 Go 中的闭包
Go 中的函数是一等公民,之前写过一篇文章:函数是一等公民,这到底在说什么?

日常开发中,闭包是很常见的。举几个例子。

标准库
在 net/http 包中的函数 ProxyURL,实现如下:

// ProxyURL returns a proxy function (for use in a Transport)
// that always returns the same URL.
func ProxyURL(fixedURL *url.URL) func(*Request) (*url.URL, error) {
	return func(*Request) (*url.URL, error) {
		return fixedURL, nil
	}
}

它的返回值是另一个函数,签名是:

func(*Request) (*url.URL, error)

在返回的函数中,引用了父函数(ProxyURL)的参数 fixedURL,因此这是闭包。

03 总结
通过以上的讲解,对闭包应该有了更清晰的认识。如果面试中再被问到闭包,你可以这么回答:

对闭包来说,函数在该语言中得是一等公民。一般来说,一个函数返回另外一个函数,这个被返回的函数可以引用外层函数的局部变量,这形成了一个闭包。通常,闭包通过一个结构体来实现,它存储一个函数和一个关联的上下文环境。但 Go 语言中,匿名函数就是一个闭包,它可以直接引用外部函数的局部变量,因为 Go 规范和 FAQ 都这么说了。

面试官会不会被你惊到:原来如此,后一种说法我之前没有注意过。


周知博客, 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:go语言问题(闭包)
喜欢 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址