闭包

基本介绍: 闭包就是一个函数和与其相关的引用环境组合的一个整体(实体)

案例演示:

package main
import (
  "fmt"
)

//累加器
func AddUpper() func (int) int {
  var n int = 10
  return func (x int) int {
    n = n + x
    return n
  }
}

func main() {
  //使用上面的代码
  f := AddUpper()
  fmt.Println(f(1))   //11
  fmt.Println(f(2))   //13
  fmt.Println(f(3))   //16

}

对上面代码的说明和总结:

1)AddUpper 是一个函数,返回的数据类型是func (int) int。

2)闭包的说明:

  var n int = 10
  return func (x int) int {
    n = n + x
    return n
  }

返回的是一个匿名函数,但是这个匿名函数引用到函数外的n, 所以这个匿名函数就和n形成一个整体,构成闭包。


3)可以这样理解:闭包是类,函数是操作,n是字段。函数和它使用到的n构成闭包。

4)当我们反复的调用 f 函数时,因为 n 是初始化一次,因此每调用一次就进行累计。

5)我们要搞清楚闭包的关键,就是要分析出返回的函数它使用(引用)到哪些变量,因为函数和它引用到的变量共同构成闭包。

6)对上面的代码的一个修改,加深对闭包的理解

package main
import (
"fmt"
)

//累加器
func AddUpper() func (int) int {
  var n int = 10
  var str = "hello"
  return func (x int) int {
    n = n + x
    str += string(36)
    fmt.Println("str = ", str)   //1.str="hello$" 2.str="hello$$" 3.str="hello$$$"
    return n
  }
}

func main() {
  //使用前面的代码
  f := AddUpper()
  fmt.Println(f(1))   //11
  fmt.Println(f(2))   //13
  fmt.Println(f(3))   //16
}

 

闭包的最佳实践:

请编写一个程序,具体要求如下:

1)编写一个函数 makeSuffix(suffix string) 可以接收一个文件后缀名(比如.jpg),并返回一个闭包

2)调用闭包,可以传入一个文件名,如果该文件名没有指定的后缀(比如.jpg),则返回 文件名.jpg,如果已经有.jpg后缀,则返回源文件名。

3)要求使用闭包的方式完成

4)strings.HasSuffix

函数HasSuffix:

  func HasSuffix(s, suffix string) bool
  判断s是否有后缀字符串suffix。


代码:

package main
import (
"fmt"
"strings"
)

func makeSuffix(suffix string) func (string) string {
  return func (name string) string {
    //如果 name 没有指定后缀,则加上,否则就返回原来的名字
    if !strings.HasSuffix(name, suffix) {
      return name + suffix
    }
    return name
  }

}

func main() {

  //返回一个闭包
  f := makeSuffix(".jpg") //如果使用闭包完成,好处是只需要传入一次后缀
  //测试makeSuffix 的使用
  fmt.Println("文件名处理后=", f("winter"))
  fmt.Println("文件名处理后=", f("bird.jpg"))
}


代码说明:

1)返回的匿名函数和 makeSuffix(suffix string) 里面的 suffix 变量 和返回的函数组合成一个闭包,因为返回的函数引用到suffix这个变量

2)我们体会一下闭包的好处,如果使用传统的方法,也可以轻松实现这个功能,但是传统方法需要每次都传入 后缀名,比如.jpg,而闭包因为可以保留上次引用的某个值,所以我们传入一次就可以反复使用。

传统方法的例子:

func makeSuffix2(suffix string, name string) string {

  //如果 name 没有指定后缀,则加上,否则就返回原来的名字
  if !strings.HasSuffix(name, suffix) {
    return name + suffix
  }
  return name
}

func main() {

  fmt.Println("文件名处理后=", makeSuffix2("jpg","winter"))    //每次都得传后缀名
  fmt.Println("文件名处理后=", makeSuffix2("jpg","bird.jpg"))
}

 

posted @ 2019-08-14 22:21  我是一只忙碌的小青蛙  阅读(155)  评论(0编辑  收藏  举报