在处理程序异常时,使用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时应该是自动赋值给上面定义好的变量。
哈哈,这些都是测试所得,有不对之处还请留言指出,大家共同进步