下面由go语言?教程栏目给大家介绍关于go 闭包的学习使用,希望对需要的朋友有所帮助!
下面由go语言教程栏目给大家介绍关于go 闭包的学习使用,希望对需要的朋友有所帮助!
go闭包 在 Golang 中,闭包是一个可以引用其作用域之外变量的函数。 匿名函数 顾名思义,匿名函数就是没有名字的函数。 package mainimport ( "fmt")func sayhi1() { // 一般函数 fmt.Println("hello golang, I am Regular function")}func main() { sayhi1() sayhi2 := func() { //匿名函数 fmt.Println("hello golang, I am Anonymous function") } sayhi2()} 结果输出: hello golang, I am Regular functionhello golang, I am Anonymous function 通过创建一个返回函数的函数来使用匿名函数。 package mainimport ( "fmt")func sayhello(s string) func() { return func() { fmt.Println("hello", s) }}func main() { sayhello := sayhello("golang") sayhello()} 结果输出: hello golang 常规函数和匿名函数唯一区别是匿名函数不是在包级别声明的,它们被动态地声明,通常要么被使用,要么被遗忘,要么被分配给一个变量供以后使用。 闭包的本质 闭包是包含自由变量的代码块,这些变量不在这个代码块内或者任何全局上下文中定义,而是在定义代码块的环境中定义。由于自由变量包含在代码块中,所以只要闭包还被使用,那么这些自由变量以及它们引用的对象就不会被释放,要执行的代码为自由变量提供绑定的计算环境。 Golang中的闭包同样也会引用到函数外的变量,闭包的实现确保只要闭包还被使用,那么被闭包引用的变量会一直存在。从形式上看,匿名函数都是闭包。 package mainimport ( "fmt")func caller() func() int { callerd := 1 sum := 0 return func() int { sum += callerd return sum }}func main() { next := caller() fmt.Println(next()) fmt.Println(next()) fmt.Println(next())} 结果输出: 1 2 3 该例子中called 和sum 是自由变量,caller函数返回的匿名函数为自由变量提供了计算环境,匿名函数和自由变量组成的代码块其实就是闭包。在闭包函数中,只有匿名函数才能访问自由变量called和sum,而无法通过其他途径访问,因此闭包自由变量的安全性。 现在我们给出引用环境的定义:在程序执行中的某个点所有处于活跃状态的约束所组成的集合,其中的约束指的是一个变量的名字和其所代表的对象之间的联系。 其实我们可以将闭包函数看成一个类(C++),一个闭包函数调用就是实例化一个对象,闭包的自由变量就是类的成员变量,闭包函数的参数就是类的函数对象的参数。在该例子中,next可以看作是实例化的一个对象,next()可以看做是对象函数调用的返回值。 闭包使用的一些例子
package mainimport ( "fmt")func caller() func() int { callerd := 0 return func() int { callerd++ return callerd }}func main() { next := caller() fmt.Println(next()) fmt.Println(next()) fmt.Println(next())} 结果输出: 1 2 3
package mainimport ( "fmt" "net/http")func main() { http.HandleFunc("/hello", hello) http.ListenAndServe(":3000", nil)}func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "<h1>Hello!</h1>")} 在上面例子中,函数 hello() 被传递给 http.HandleFunc() 函数,并在该路由匹配时调用。 package mainimport ( "fmt" "net/http" "time")func main() { http.HandleFunc("/hello", timed(hello)) http.ListenAndServe(":3000", nil)}func timed(f func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { start := time.Now() f(w, r) end := time.Now() fmt.Println("The request took", end.Sub(start)) }}func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "<h1>Hello!</h1>")} timed() 函数接受一个可以用作处理函数的函数,并返回一个相同类型的函数,但返回的函数与传递它的函数不同。返回的闭包记录当前时间,调用原始函数,最后记录结束时间并打印出请求的持续时间。同时对我们的处理程序函数内部实际发生的事情是不可知的。
package mainimport ( "fmt" "sort")func main() { numbers := []int{1, 11, -5, 7, 2, 0, 12} sort.Ints(numbers) fmt.Println("Sorted:", numbers) index := sort.SearchInts(numbers, 7) fmt.Println("7 is at index:", index)} 结果输出: Sorted: [-5 0 1 2 7 11 12]7 is at index: 4 如果要搜索的每个元素都是自定义类型的切片会发生什么?或者,如果您想找到第一个等于或大于 7 的数字的索引,而不仅仅是 7 的第一个索引? package mainimport ( "fmt" "sort")func main() { numbers := []int{1, 11, -5, 8, 2, 0, 12} sort.Ints(numbers) fmt.Println("Sorted:", numbers) index := sort.Search(len(numbers), func(i int) bool { return numbers[i] >= 7 }) fmt.Println("The first number >= 7 is at index:", index) fmt.Println("The first number >= 7 is:", numbers[index])} 结果输出: Sorted: [-5 0 1 2 8 11 12]The first number >= 7 is at index: 4 The first number >= 7 is: 8 在这个例子中,我们的闭包是作为第二个参数传递给 sort.Search() 的简单函数。
package mainimport ( "fmt")func handle() { defer func() { err := recover() if err != nil { fmt.Println("some except had happend:", err) } }() var a *int = nil *a = 100}func main() { handle()} 结果输出: some except had happend: runtime error: invalid memory address or nil pointer dereference recover函数用于终止错误处理流程。一般情况下,recover应该在一个使用defer关键字的函数中执行以有效截取错误处理流程。如果没有在发生异常的goroutine中明确调用恢复过程(调用recover函数),会导致该goroutine所属的进程打印异常信息后直接退出
以上就是分享优质笔记:go闭包的使用学习的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |