这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天
今天开例会讨论问题和排查bug的时候,有组员问为什么封了一层就拿不到数据了。
这里做一下简单复现。
代码如下,就是 Hertz 的示例代码
import (
"context"
"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, rc *app.RequestContext) {
data := []int{1, 2, 3} // 模拟数据库中查询到的数据
rc.JSON(consts.StatusOK, data)
})
h.Spin()
}
新建一个终端,然后使用curl命令做个测试(用Postman或者其他能发请求的测试工具也行)
curl http://127.0.0.1:8888/ping
结果(已简化)
RawContent : HTTP/1.1 200 OK
Content-Length: 7
Content-Type: application/json; charset=utf-8
Date: Wed, 18 Jan 2023 15:34:18 GMT
Server: hertz
[1,2,3]
可以看到是能正常拿到数据的。
然后将结果封装一层。
type result struct {
code int
data []int
}
func main() {
h := server.Default()
h.GET("/ping", func(c context.Context, rc *app.RequestContext) {
data := []int{1, 2, 3} // 模拟数据库中查询到的数据
res := result{code: 0, data: data}
rc.JSON(consts.StatusOK, res)
})
h.Spin()
}
然后执行同样的测试命令,结果却是
RawContent : HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Date: Wed, 18 Jan 2023 15:40:27 GMT
Server: hertz
{}
body 变成了一个空对象。
这是一个对于初学者来说比较经典的问题了。在Go语言中,以大写开头的字段才能被其他包所访问(暂时不考虑反射),小写的字段仅在当前包下可见。
改成大写后,问题就消失了。
既然进行JSON序列化的时候会忽略命名为小写开头的字段,而JSON序列化的包一般是通过反射获取结构体中的字段。
那么究竟是反射无法获取到小写开头的字段还是能获取而不去用呢。
我们可以写个Demo来验证下。
另外新建一个包 result
type Result struct {
code int
data []int
}
code 和 data 都是小写,是私有变量,故在 result 包外无法直接访问。
在 result 包外写一个简单的反射 Demo。
package main
import (
"reflect"
"reflectDemo/result"
)
func main() {
r := result.Result{}
t := reflect.TypeOf(r)
println(t.NumField())
for i := 0; i < t.NumField(); i++ {
println(t.Field(i).Name)
}
}
运行结果如下
2
code
data
故结论是能获取(和 Java 中反射能获取到 private 修饰的字段是一个道理),但是并不会进行序列化。