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條經驗 獲得超8個贊
我認為 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 關注
- 444 瀏覽
添加回答
舉報