记一次:发生错误,但是defer错误没有生效的情况

在处理程序异常时,使用defer能够很大程度检查代码量,提高码字效率。

但是,却发现一件很奇怪的事情,defer中的err竟然失效了!!!

这时一万个为什么瞬间闪现脑海,因为之前一直这样码的呀?

代码:

    var err error
    var Error string = "success"
    defer func() {
        if err != nil {this.Data["Error"] = Error
            this.TplName = "layout/error.html"
        }
    }()

    name := strings.TrimSpace(this.GetString("activity_name"))
    if len(name) == 0 {
        Error = "活动的名字不能为空"
        err = fmt.Errorf("activity name can not null")
        return
    }

上面是我的平时代码,没有问题,错误提醒ok

错误代码:

    var err error
    var Error string = "success"
    defer func() {if err != nil {
            fmt.Println("add_activity,defer1-1:",Error)
            this.Data["Error"] = Error
            this.TplName = "layout/error.html"
        }
    }()

    ....省略n行代码

    productId := this.GetStrings("product_id")
    if len(productId) == 0 {
        err = fmt.Errorf("商品id 非法, err:%v", err)
        Error = err.Error()
        return
    }

    //处理活动商品信息
    var productList = make([]model.SeckillActivityProduct, len(productId))
    for k, v := range productId {
        idInt, err := strconv.Atoi(v)
        if err != nil {
            err = fmt.Errorf("idInt atoi failed ,product id=[%s] err:%v\n", v, err)
            Error = err.Error()
            return
        }
        productList[k].ProductId = idInt
        seckillPriceFloat64, err := strconv.ParseFloat(seckillPriceArr[k], 64)
        if err != nil {
            err = fmt.Errorf("seckillPriceFloat64 ParseFloat failed ,product id=[%s] err:%v\n", v, err)
            Error = err.Error()
            return
        }
        totalInt, err := strconv.Atoi(totalArr[k])
        if err != nil {
            err = fmt.Errorf("totalInt atoi failed ,product id=[%s] err:%v\n", v, err)
            Error = err.Error()
            return
        }
        SeckillProductIdInt, errMsg := strconv.Atoi(seckillProductIdArr[k])
        fmt.Println("add_activity3-5")
        if errMsg != nil {
            err = fmt.Errorf("SeckillProductIdInt atoi failed ,product id=[%s] err:%v\n", v, errMsg)
            Error = err.Error()return
        }
        productList[k].SeckillPrice = seckillPriceFloat64
        productList[k].Total = totalInt
        productList[k].Id = SeckillProductIdInt
    }

上面代码执行请求后,错误竟然没有提醒!why?

第一反应不可能,一直这样的呀。

后来想到golang和php的作用域用法不同,就各种修改,问题依然...

自学golang一段时间了,golang属于静态语言广泛使用内存地址,就想到会不会是内存地址被修改了,而上面defer还是使用原来的内存地址呢?

于是大量断点,果然...,在一个循环中发现err := 函数()的时候err的内存地址被修改了。于是改之,问题解决。

在这里总结下:

  定义完重要变量后,千万不要再在非必要地方重复使用这个变量名,防止滥用产生不必要麻烦。

  同时,我看到网上有人说是引用类型问题,即应这样定义var err *Error。但是,测试后发现在同一个函数下,defer后,return前返回err仍然地址相同。所以应该不是值类型和引用类型问题,当然嵌套多函数就另说了。所以,在一个函数下,renturn时应该是自动赋值给上面定义好的变量。

哈哈,这些都是测试所得,有不对之处还请留言指出,大家共同进步

 

上一篇:扩展 GRTN:云原生趋势下的 RTC 架构演进


下一篇:golang 字符串拼接性能比较