美文网首页我爱编程
golang 闭包使用注意

golang 闭包使用注意

作者: Jancd | 来源:发表于2018-06-21 17:16 被阅读137次

 go只提供了一种循环方式,即for循环,在使用时可以像c那样使用,也可以通过for range方式遍历容器类型如数组、切片和映射。但是在使用for range时,如果使用不当,就会出现一些问题,导致程序运行行为不如预期。

情形 . 一

> for range + 闭包 代码如下:

package main
import (
    "fmt"
    "time"
)
func main()  {
    str := []string{"I","am","Ethan"}
    for _,v := range str{
        go func() {
            fmt.Println(v)
        }()
    }
    time.Sleep(3 * time.Second)
}
----------
输出结果:
Ethan
Ethan
Ethan

 程序设计的原意是遍历字符串切片并将其打印出来,可是输出结果却只输出了切片的最后一个元素.

  原因是 : 闭包里引用了不作为参数传递进去的值,都是引用传递...也就是说,println(v) 其实是引用了v的地址然后解引用,将值打印出来..等到这个goroutine执行println(v)的时候,v所指向的值已经是"Ethan"


 如果要正确打印,在定义闭包的时候要定义一个参数,将v作为参数传递进去.修改后代码如下:

package main
import (
    "fmt"
    "time"
)
func main()  {
    str := []string{"I","am","Ethan"}
    for _,v := range str{
        go func(v string) {
            fmt.Println(v)
        }(v)
    }
    time.Sleep(3 * time.Second)
}

此外,输出结果不一定是 i am Ethan,因为goroutine执行顺序有go runtime调度器决定


情形 . 二

> 操作map,原理和情形一类似 代码如下:

package main

import "fmt"

func main() {
    slice := []int{0, 1, 2, 3}
    myMap := make(map[int]*int)

    for index , value := range slice {
        myMap[index] = &value
    }
    prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
    for key, value := range myMap {
        fmt.Printf("map[%v]=%v\n", key, *value)
    }
}
----------
输出结果:
map[0]=3
map[1]=3
map[2]=3
map[3]=3

 原因解释:但是由输出可以知道,映射的值都相同且都是3。其实可以猜测映射的值都是同一个地址,遍历到切片的最后一个元素3时,将3写入了该地址,所以导致映射所有值都相同。

 其实真实原因也是如此,因为for range创建了每个元素的副本,而不是直接返回每个元素的引用,如果使用该值变量的地址作为指向每个元素的指针,就会导致错误,在迭代时,返回的变量是一个迭代过程中根据切片依次赋值的新变量,所以值的地址总是相同的,导致结果不如预期。


做一下小小的修改就能得到我们的预期结果:

package main

import "fmt"

func main() {
    slice := []int{0, 1, 2, 3}
    myMap := make(map[int]*int)

    for index , value := range slice {
        v := value
        myMap[index] = &v
    }
    prtMap(myMap)
}

func prtMap(myMap map[int]*int) {
    for key, value := range myMap {
        fmt.Printf("map[%v]=%v\n", key, *value)
    }
}

相关文章

  • golang 闭包使用注意

     go只提供了一种循环方式,即for循环,在使用时可以像c那样使用,也可以通过for range方式遍历容器类型如...

  • groovy-闭包

    定义和执行闭包 闭包作为参数返回 闭包作为参数传递 闭包使用外部变量 注意: 闭包可使用(引用)闭包外部定义的变量...

  • golang sort.Slice

    sort.Slice是golang提供的切片排序方法, 其中使用到了反射(reflect)包 使用了闭包 可以参考...

  • Closure in Golang

    序言 Golang遵循“少即是多”的设计哲学,同时又支持闭包(Closure),那么闭包对于Golang来说肯定有...

  • 前端面试题

    1 ,什么是闭包?闭包有什么好处?使用闭包要注意什么? 详情可参考:http://www.jianshu.com/...

  • 面试题(day-2)

    1 ,什么是闭包?闭包有什么好处?使用闭包要注意什么? 闭包:函数嵌套函数,内部函数可以引用外部函数的参数和变量,...

  • GO语言面试系列:(三)关于golang闭包所谓的“坑”

    关于golang闭包所谓的“坑”,昨天听了某企业架构师关于golang的经验分享,听到架构师吐槽golang里的闭...

  • 08. Go极简教程 函数及闭包

    Golang中, 函数是一等公民, 以下简要描述函数的使用 函数的声明 闭包 引用官方的解释: Go 函数可以是闭...

  • golang闭包

    闭包的安全性与变量生命周期

  • Golang 闭包

    输出:

网友评论

    本文标题:golang 闭包使用注意

    本文链接:https://www.haomeiwen.com/subject/csrcyftx.html