Golang JSON Tag 匹配问题

现象

type X struct {
    Data string `json:"data"`
}

func main() {
    var b = []byte(`{"DATA":"xxx"}`)
    x := &X{}
    _ = json.Unmarshal(b, x)
    fmt.Println(x) // 输出: &{xxx}
}

疑问

json tag 不相等,即 data != DATA 为啥还可以反序列化成功呢?

源码

go/src/encoding/json/fold.go:foldFunc

// foldFunc returns one of four different case folding equivalence
// functions, from most general (and slow) to fastest:
//
// 1) bytes.EqualFold, if the key s contains any non-ASCII UTF-8
// 2) equalFoldRight, if s contains special folding ASCII ('k', 'K', 's', 'S')
// 3) asciiEqualFold, no special, but includes non-letters (including _)
// 4) simpleLetterEqualFold, no specials, no non-letters.
//
// The letters S and K are special because they map to 3 runes, not just 2:
//  * S maps to s and to U+017F 'ſ' Latin small letter long s
//  * k maps to K and to U+212A 'K' Kelvin sign
// See https://play.golang.org/p/tTxjOc0OGo
//
// The returned function is specialized for matching against s and
// should only be given s. It's not curried for performance reasons.
func foldFunc(s []byte) func(s, t []byte) bool {
    nonLetter := false
    special := false // special letter
    for _, b := range s {
        if b >= utf8.RuneSelf {
            return bytes.EqualFold
        }
        upper := b & caseMask
        if upper < 'A' || upper > 'Z' {
            nonLetter = true
        } else if upper == 'K' || upper == 'S' {
            // See above for why these letters are special.
            special = true
        }
    }
    if special {
        return equalFoldRight
    }
    if nonLetter {
        return asciiEqualFold
    }
    return simpleLetterEqualFold
}

看注释还是挺容易理解的,主要分 4 种匹配场景。

然后在 decode.go 文件的 func (d *decodeState) object(v reflect.Value) error 函数。

如果 tag 相等逻辑继续,否则通过 foldFunc 判断。

var f *field
if i, ok := fields.nameIndex[string(key)]; ok {
    // Found an exact name match.
    f = &fields.list[i]
} else {
    // Fall back to the expensive case-insensitive
    // linear search.
    for i := range fields.list {
        ff := &fields.list[i]
        if ff.equalFold(ff.nameBytes, key) {
            f = ff
            break
        }
    }
}

结果

嗯,所以出现了上述的问题。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容