匿名函数:所谓匿名函数,就是没有名字的函数
定义匿名函数
func(x,y int) int {
return x + y
}
匿名函数作为返回值
func getPrintMessage() func(string) {
// returns an anonymous function
return func(message string) {
fmt.Println(message)
}
}
匿名函数赋给变量
f := func() int {
...
}
返回多个匿名函数
func calc(x, y int) (func(int), func()) {
f1 := func(z int) int {
return (x + y) * z / 2
}
f2 := func() int {
return 2 * (x + y)
}
return f1, f2
}
完整代码:
package main
import "fmt"
func showMessage(message string) {
fmt.Println(message)
}
func getPrintMessage() func(string) {
// returns an anonymous function
return func(message string) {
fmt.Println(message)
}
}
func main() {
// named function
showMessage("Hello function!")
// anonymous function declared and called
func(message string) {
fmt.Println(message)
}("Hello anonymous function!")
// gets anonymous function and calls it
printfunc := getPrintMessage()
printfunc("Hello anonymous function using caller!")
}
输出:
Hello function!
Hello anonymous function!
Hello anonymous function using caller!
闭包的概念:闭包就是能够读取其他函数内部变量的函数。 只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成”定义在一个函数内部的函数”。
golang中使用闭包
package main
import "fmt"
func outer(name string) {
// variable in outer function
text := "Modified " + name
// foo is a inner function and has access to text variable, is a closure
// closures have access to variables even after exiting this block
foo := func() {
fmt.Println(text)
}
// calling the closure
foo()
}
func main() {
outer("hello")
}
返回闭包
package main
import "fmt"
func outer(name string) func() {
// variable
text := "Modified " + name
// closure. function has access to text even after exiting this block
foo := func() {
fmt.Println(text)
}
// return the closure
return foo
}
func main() {
// foo is a closure
foo := outer("hello")
// calling a closure
foo()
}
Closures and state
package main
import "fmt"
func counter(start int) (func() int, func()) {
// if the value gets mutated, the same is reflected in closure
ctr := func() int {
return start
}
incr := func() {
start++
}
// both ctr and incr have same reference to start
// closures are created, but are not called
return ctr, incr
}
func main() {
// ctr, incr and ctr1, incr1 are different
ctr, incr := counter(100)
ctr1, incr1 := counter(100)
fmt.Println("counter - ", ctr())
fmt.Println("counter1 - ", ctr1())
// incr by 1
incr()
fmt.Println("counter - ", ctr())
fmt.Println("counter1- ", ctr1())
// incr1 by 2
incr1()
incr1()
fmt.Println("counter - ", ctr())
fmt.Println("counter1- ", ctr1())
}
陷阱
package main
import "fmt"
func functions() []func() {
// pitfall of using loop variables
arr := []int{1, 2, 3, 4}
result := make([]func(), 0)
for i := range arr {
result = append(result, func() { fmt.Printf("index - %d, value - %d\n", i, arr[i]) })
}
return result
}
func main() {
fns := functions()
for f := range fns {
fns[f]()
}
}
输出:
index - 3, value - 4
index - 3, value - 4
index - 3, value - 4
index - 3, value - 4
传址会修改原数据
func main() {
x := [3]int{1,2,3}
func(arr *[3]int) {
(*arr)[0] = 7
fmt.Println(arr) // &[7 2 3]
}(&x)
fmt.Println(x) // [7 2 3]
}
斐波拉切数列
package main
import "fmt"
// fibonacci is a function that returns
// a function that returns an int.
func fibonacci() func() int {
x, y := 0, 1
return func() int {
x, y = y, x+y
return x
}
}
func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}
for 语句中的迭代变量与闭包函数
for 语句中的迭代变量在每次迭代中都会重用,即 for 中创建的闭包函数接收到的参数始终是同一个变量,在 goroutine 开始执行时都会得到同一个迭代值:
func main() {
data := []string{"one", "two", "three"}
for _, v := range data {
go func() {
fmt.Println(v)
}()
}
time.Sleep(3 * time.Second)
// 输出 three three three
}
修改一:最简单的解决方法:无需修改 goroutine 函数,在 for 内部使用局部变量保存迭代值,再传参:
func main() {
data := []string{"one", "two", "three"}
for _, v := range data {
vCopy := v
go func() {
fmt.Println(vCopy)
}()
}
time.Sleep(3 * time.Second)
// 输出 one two three
}
另一个解决方法:直接将当前的迭代值以参数形式传递给匿名函数:
func main() {
data := []string{"one", "two", "three"}
for _, v := range data {
go func(in string) {
fmt.Println(in)
}(v)
}
time.Sleep(3 * time.Second)
// 输出 one two three
}