3 回答
TA贡献1799条经验 获得超6个赞
简短回答:在当前的json实现中,不可能只使用struct tags。
注意:这是一个实现限制,而不是规范限制。(这是json包实现的限制,而不是结构标签规范的限制。)
一些背景:您使用原始字符串文字指定了标签:
原始字符串文字的值是由引号之间的未解释(隐式 UTF-8 编码)字符组成的字符串...
因此,编译器不会在原始字符串文字的内容中进行转义或取消引用。
引用自 struct 标记值的约定reflect.StructTag:
按照惯例,标签字符串是可选的空格分隔键:“值”对的串联。每个键都是一个非空字符串,由除空格 (U+0020 ' ')、引号 (U+0022 '"') 和冒号 (U+003A ':') 以外的非控制字符组成。每个值都用引号引起来使用 U+0022 '"' 字符和 Go 字符串文字语法。
这意味着按照惯例标签值是由空格分隔的 (key:"value") 对列表。有钥匙不少限制,但值可以是任何东西,和值(应该)使用“去串文字语法”,这意味着这些值将在运行时从代码中加引号(通过一个电话strconv.Unquote(),叫from StructTag.Get(),在源文件reflect/type.go,当前行 #809)。
所以不需要双引号。请参阅您的简化示例:
type Response1 struct {
Page int
Fruits []string
Msg interface{} `json:"\u0000_abc"`
}
现在下面的代码:
t := reflect.TypeOf(Response1{})
fmt.Printf("%#v\n", t.Field(2).Tag)
fmt.Printf("%#v\n", t.Field(2).Tag.Get("json"))
印刷:
"json:\"\\u0000_abc\""
"\x00_abc"
如您所见,json键的值部分是"\x00_abc"正确包含零字符的。
但是json包将如何使用它?
该json包使用返回的值StructTag.Get()(从reflect包装),正是我们所做的。您可以在json/encode.go源文件typeFields()函数中看到它,当前行 #1032。到现在为止还挺好。
然后它调用源文件中未导出的json.parseTag()函数json/tags.go,当前行#17。这会剪切逗号后面的部分(成为“标签选项”)。
最后json.isValidTag()使用源文件中的前一个值调用函数json/encode.go,当前行#731。此函数检查传递的符文string,并且(除了一组预定义的允许字符"!#$%&()*+-./:<=>?@[]^_{|}~ ")拒绝不是 Unicode 字母或数字(由unicode.IsLetter()和定义unicode.IsDigit())的所有内容:
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
return false
}
'\u0000' 不是预定义的允许字符的一部分,您现在可以猜到,它既不是字母也不是数字:
// Following code prints "INVALID":
c := '\u0000'
if !unicode.IsLetter(c) && !unicode.IsDigit(c) {
fmt.Println("INVALID")
}
并且由于isValidTag()返回false,name(这是json键的值,没有“标签选项”部分)将被丢弃(name = "")并且不被使用。因此,将找不到包含 unicode 零的 struct 字段的匹配项。
对于替代解决方案,请使用map、自定义json.Unmarshaler或使用json.RawMessage。
但我非常不鼓励使用这种丑陋的 json 键。我知道您可能只是想解析这样的 json 响应,它可能超出您的范围,但是您应该反对使用这些键,因为它们只会在以后引起更多问题(例如,如果存储在 db 中,通过检查记录它会很难发现其中有'\u0000'字符,因为它们可能会显示为空)。
TA贡献2039条经验 获得超7个赞
我认为 struct 标签不可能做到这一点。您可以做的最好的事情是将其解组map[string]interface{},然后手动获取值:
var b = []byte(`{"\u0000abc":42}`)
var m map[string]interface{}
err := json.Unmarshal(b, &m)
if err != nil {
panic(err)
}
fmt.Println(m, m["\x00abc"])
游乐场:http : //play.golang.org/p/RtS7Nst0d7。
TA贡献1784条经验 获得超8个赞
由于以下原因,您不能这样做:http : //golang.org/ref/spec#Struct_types
但是您可以解组,map[string]interface{}
然后通过regexp检查该对象的字段名称。
- 3 回答
- 0 关注
- 366 浏览
添加回答
举报