下面由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)其它相关文章! |
