写golang restful接口时遇到的一个坑
来源:互联网 发布:淘宝游戏王正版 编辑:程序博客网 时间:2024/06/06 07:17
话不多说,先上代码
type detail struct { High float64 `json:"high"` Low float64 `json:"low"` Average float64 `json:"average"`}type Spot struct { UpdateDate string `json:"update_date"` Detail []detail `json:"detail"`} . .//此处省略部分无关代码 . key := constant.REDIS_INFIX_PREMIUM + productId //此处是去redis读数据 d, err := c.ZRevRangeByScore(key, maxScores, minScores, page, num)//取出的[][]byte放入d中 if err != nil { logger.Warnning(err) return nil, err } var ( prices []Spot p Spot ) for _, v := range d { //遍历[][]byte err = json.Unmarshal(v, &p) //反序列化赋给p if err != nil { logger.Warnning(err) return nil, err } prices = append(prices, p) //每个价格点都加入到prices切片中,然后返回 } return prices, nil
乍一看这段代码没什么问题,但是实际上调试的时候,发现prices切片中的每个元素,也就是每个Spot对象的Detail字段都是一模一样的(UpdateDate字段没问题),一开始怀疑是存redis时出了问题,后来发现redis里的内容是对的。
让我来加入一些调试代码,把地址什么的都打印出来:
for _, v := range d { //遍历[][]byte err = json.Unmarshal(v, &p) //反序列化赋给p fmt.Printf("p的Detail的Data的地址: %p \n",p.Sli)//每次循环打印p的Detail的Data的地址 if err != nil { logger.Warnning(err) return nil, err } prices = append(prices, p) //每个价格点都加入到prices切片中,然后返回 } fmt.Println(prices) //打印每个p的内容 . . . 打印结果: p的Detail的Data的地址: 0xc0420420c0 p的Detail的Data的地址: 0xc0420420c0 //指向的地址未发生改变 [{2017-11-08 [{250 750 500} {250 750 500}]} {2017-11-09 [{250 750 500} {250 750 500}]}] //日期后面就是Detail字段,发现都变得一模一样
后来排查了很久,其实是因为p内部包含了一个切片,也就是Detail,然后这个切片会指向一个地址,真正的Data是存在这个地址中的,如果切片容量够的情况下,是不会改变指向的地址的。这就导致了,最后一个Spot对象的Detail切片的Data覆盖了之前append进去的所有Spot对象的Detail的Data,因为它们指向的都是一个地址,要改变当然一起改变了。看上面的地址。
其实修改起来很简单,只要把var p Spot
加到循环中,而不是放在循环外面就可以了。道理很简单,每次新建变量的时候,Detail会指向一个新的地址。
for _, v := range d { var p Spot //变量申明放入循环内 err = json.Unmarshal(v, &p) fmt.Printf("p的Detail的Data的地址: %p \n",p.Sli)//每次循环打印p的Detail的Data的地址 if err != nil { logger.Warnning(err) return nil, err } prices = append(prices, p) } fmt.Println(prices) //打印每个p的内容 . . . 打印结果: p的Detail的Data的地址: 0xc0420420c0 p的Detail的Data的地址: 0xc042042120 //地址改变了 [{2017-11-08 [{500 600 550} {500 600 550}]} {2017-11-09 [{250 750 500} {250 750 500}]}] //结果正确了
后来又发现,其实还有个方法可以避免这个问题,就是在申明结构体的时候,不要把Detail定义为Slice,定义为一个空的interface就行,但是传的时候还是传切片,在Unmarshal的时候,golang发现这是个空接口,就会去给它申请新的地址,后来验证是没问题的,即:
type Spot struct { UpdateDate string `json:"update_date"` Detail interface{} `json:"detail"`}
之前自以为对slice很熟悉,也知道它的内部结构是会指向一个地址的,但是真正用起来还是要多加注意,一不小心就忽略了,引以为戒啊。
阅读全文
1 0
- 写golang restful接口时遇到的一个坑
- yii2 RESTful 接口 api -6: 写一个自己的api
- Jersey 写restful接口时QueryParam ,FormParam 等的区别
- 【SpringMVC】用restful风格接口写DELETE或PUT请求时遇到405错误
- 接口开发,写接口文档时遇到的问题
- 使用golang遇到的坑
- 用golang写的一个链表
- 写的一个接口
- 写一个gson遇到的坑
- 写Dll时遇到的一个错误
- golang 实现一个restful微服务
- Jersey写Restful接口获取参数的问题
- Jersey写Restful接口获取参数的问题
- golang http.FileServer 遇到的坑
- 关于spring restful使用中遇到的一个性能问题
- Golang 的一个小坑
- 记录golang 的一个坑
- 用Golang写一个搜索引擎
- HDOJ 1406 完数
- transform、transition、animation区别
- JSP中请求转发何请求重定向的区别
- 1!+2!+...+n!
- HTML CSS
- 写golang restful接口时遇到的一个坑
- SSM---访问后台提示HTTP Status 404
- 关于Server Tomcat v9.0 Server at localhost failed to start.的分析
- Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qua
- javaweb中的过滤器学习总结(1)---myeclipse下的第一个Filter
- JAVA中JButton常用设置
- WEBGL学习【十】运动模型
- 《HTML之base标签》
- hadoop 文件分块,block与split关系