匿名函数
func main() {
//匿名函数使用
str := strings.Map(func(r rune) rune {
return r + 2;
}, "1234567")
fmt.Println(str)
f := squ()
fmt.Println(f()) //
fmt.Println(f())
fmt.Println(f())
}
func squ() func() int {
x:=0
return func() int {
x++
return x * x
}
}
匿名函数迭代变量问题
func main() {
//这个函数存在迭代遍历错误的事例,
//d是循环生成的变量,在一个作用块进行声明,在循环里面
//创建的所有函数都使用固定的变量,因为回调函数后面在调用
//因此回调函数d变量实际取值都是循环的最后一次变量
//修改方法是在循环里面定义一个临时变量,defer函数也会存在这样的问题
var rmdirs []func()
/* 错误实力
for _,d := range tempDirs() {
os.MkdirAll(d,0755)
rmdirs = append(rmdirs, func() {
os.RemoveAll(d)
})
}
*/
//修改方法在循环体里定义一个变量
for _,d := range tempDirs() {
d:= d
os.MkdirAll(d,0755)
rmdirs = append(rmdirs, func() {
os.RemoveAll(d)
})
}
//一些处理
for _,rmdir := range rmdirs {
rmdir()//清理
}
}
解决这种问题的最简单方式就是在循环里定义一个变量,接受循环的值
defer延迟调用函数
- defer延迟调用,相当于使用栈的形式,随着函数的调用接受,先入后出的方式调用defer函数,此函数在循环中也存在上面的迭代变量问题
func main() {
bigSlowOperation()
}
func bigSlowOperation() {
defer trace("bigSlowOperation")()
time.Sleep(10*time.Second)
}
func trace(msg string) func() {
start:= time.Now()
log.Printf("开始调用函数%s",msg)
return func() {
log.Printf("结束调用函数%s,%s",msg,time.Since(start))
}
}
- defer函数在return之后执行,可以拿到return之后变量的值
//需要在这里定义函数返回值的变量名称
func double(x int) (result int) {
defer func() {
fmt.Printf("double(x)=%s",result)
}()
return x+x
}
- 因为defer是在函数返回之后执行,所以在循环体里面执行的语句,可能会存在问题
//因为defer会在函数调用完成之后执行,文件打开的操作可能会用光文件描述符,改进的方法是讲defer放进一个函数中执行
func f(filenames []string) error {
for _,filename :=range filenames {
file,err:= os.Open(filename)
if err !=nil {
return err
}
defer file.Close()
}
return nil
}
//改进的方式
func f1(filenames []string) error {
for _,filename :=range filenames {
err := dofile(filename)
if err !=nil {
return err
}
}
return nil
}
//在这个函数中调用defer,一次循环会调用函数,函数执行完之后就会释放文件描述符,因此就不存在上面的问题
func dofile(filename string) error {
file,err := os.Open(filename)
if err!= nil {
return err
}
defer file.Close()
return nil
}