【golang】闭包的前置:匿名函数,回调函数

426 阅读2分钟

匿名函数

  • 比较常见的就是协程后边的内容 defer后边的
func(){
    
}()

image.png

这里在下边并发部分是非常常用的

回调函数

作业: 想要只调用一个函数完成对a,b的加减乘除。则可以传入一个函数

package awesomeProject
​
import "testing"func TestName(t *testing.T) {
  a := 1
​
  b := 5
  t.Log(Caculation(a, b, add))
  t.Log(Caculation(a, b, reduce))
}
func Caculation(a, b int, f func(a, b int) int) int {
  return f(a, b)
​
}
func add(a int, b int) int {
  return a + b
}
func reduce(a int, b int) int {
  return a - b
}
​

闭包

内层函数中有外层函数的变量,内层函数操作外层函数的变量

  • 正常局部变量随着函数的调用而创建,随着函数的结束销毁但是闭包内部的函数不会。

作业:实现一个计数器

错误演示一:这不叫闭包,这是生成的局部变量,没有动原先的

package awesomeProject
​
import "testing"func TestIn(t *testing.T) {
  f := increase
  t.Log(f())
  t.Log(f())
​
}
func increase() int {
  i := 0
  func(i int) int {
    return i + 1
  }(i)
  return i
}
​

正确写法,核心其实就是将内层函数返回

package awesomeProject
​
import "testing"
​
func TestIn(t *testing.T) {
  //执行外层函数,返回一个闭包
  f := increase()
  //得到内层函数 不断地的去执行外层函数
  t.Log(f())
  t.Log(f())
  t.Log(f())
​
}
func increase() func() int {
  i := 0
  fun := func() int {
    i = i + 1
    return i
  }
  return fun
}
​

往深里研究就是关于地址的问题

package awesomeProject
​
import (
  "fmt"
  "testing"
)
​
func TestIn(t *testing.T) {
  //执行外层函数
  f := increase()
  //得到内层函数 不断地的去执行外层函数
  t.Log(f())
  t.Log(f())
  t.Log(f())
  
  f2 := increase()
  t.Log(f2())
  t.Log(f2())
  t.Log(f())
}
func increase() func() int {
  i := 0
  fun := func() int {
    fmt.Printf("%p", &i)
    i = i + 1
    return i
  }
  return fun
}
​

image.png

这里其实可以看出来地址其实没变化,每次执行一个外层函数才会更新内部函数

  • 定义用于回调或事件处理程序的小型可重用函数
package main
​
func ProcessData(callback func(int)) {
    for i := 0; i < 10; i++ {
        callback(i)
    }
}
​
func main() {
    ProcessData(func(i int) {
        println(i)
    })
}
​
//在上面的代码中,我们在调用 ProcessData 函数时传递了一个匿名函数作为参数。
//这个匿名函数是一个闭包,它捕获了外部变量 i。该函数在每次迭代中被调用,并打印出当前迭代的值。
//因此,在这个例子中,我们使用了闭包作为回调函数,
//在ProcessData 函数中处理数据。这样可以避免全局变量的使用,提高代码可维护性。//下边的代码是不使用闭包实现回调函数,更易读
func ProcessData(callback func(int)) {
  for i := 0; i < 10; i++ {
    callback(i)
  }
}
​
func myCallback(i int) {
  println(i)
}
func TestCallback(t *testing.T) {
  ProcessData(myCallback)
}
​
  • 创建将其他函数作为参数的高阶函数
  • 实现用于 Web 框架的装饰器或中间件
  • 创建用于迭代器和其他数据处理任务的函数生成器
  • 在面向对象编程中使用的函数中封装状态和行为
  • 可以有效避免使用全局变量,保护一个值不被其他代码改变
//这里的例子看上边的计算器就行

js中的闭包与go语言中的闭包

在 JS 中,闭包是一个函数,它能够访问其外部作用域中的变量,即使这些变量在函数执行结束后也依然可用。这个特性使得闭包常常用于实现私有变量和状态维护。 在 Go 中,闭包是一个函数,它能够捕获外部作用域中的变量,并在其执行过程中使用这些变量。这个特性使得闭包常常用于实现回调函数和高阶函数。 闭包在两种语言中都是函数,但在 JS 中闭包被用来实现私有变量,在 Go 中则用来实现回调和高阶函数。

function createCounter() {
    let count = 0;
    return {
        increment() {
            count++;
        },
        getCount() {
            return count;
        }
    }
}
//私有变量得到两个值
const counter = createCounter();
counter.increment();
console.log(counter.getCount()); // prints 1
counter.increment();
console.log(counter.getCount()); // prints 2