simplejson 遇到的问题
1、项目中需要调用别人的接口获取一些信息。因为那接口字段bid在记录不存在的时候会返回int类型,在记录存在的时候会返回string类型。使用了simplejson进行json解析。然后我的预期是返回int,因此使用了MustInt()来处理。但是程序运行的时候发现有时候bid会得到0,抓日志发现对方接口也有返回,不过返回的bid类型是string类型的。(之前的印象中因为MustInt()会把字符类型的数字转为对应的int类型)。
//resp = []byte("{"ret":1,"bid":171023,"tid":1}")
jsonData, err := simplejson.NewJson(resp)
if err != nil {
fmt.Println("newjsonerrr:", err)
return 0
}
logger.GetLogger(ctx).Info("resp:" + string(resp))
var bid int
if _, exist := jsonData.CheckGet("ret"); exist {
if jsonData.Get("ret").MustInt() == 1 {
logger.GetLogger(ctx).Info(fmt.Sprintf("MustInt:%d", jsonData.Get("bid").MustInt()))
logger.GetLogger(ctx).Info(fmt.Sprintf("MustInt:%s", jsonData.Get("bid").MustString()))
logger.GetLogger(ctx).Info(fmt.Sprintf("MustInt:%d", cast.ToInt(jsonData.Get("bid").Interface())))
bid = jsonData.Get("bid").MustInt()
return bid
} else {
logger.GetLogger(ctx).Info("addbar api ret!=1!" + string(resp))
}
} else {
logger.GetLogger(ctx).Info("addbar api ret not exist!" + string(resp))
}
就去看了一下MustInt()里面的实现,发现里面有个json.Number类型,
是这么定义的:type Number string、 我错误的以为他和string是一样的类型,认为他应该走第一个case,给我返回int64类型。后面发现虽然Number是基于string定义的,但是他和string类型其实是不一样的类型的。所以如果是一个string类型,MustInt()后会变返回0。经同事提醒,我印象中能把string类型的数字转成int类型的库是cast库。
func (j *Json) Int() (int, error) {
switch j.data.(type) {
case json.Number:
i, err := j.data.(json.Number).Int64()
return int(i), err
case float32, float64:
return int(reflect.ValueOf(j.data).Float()), nil
case int, int8, int16, int32, int64:
return int(reflect.ValueOf(j.data).Int()), nil
case uint, uint8, uint16, uint32, uint64:
return int(reflect.ValueOf(j.data).Uint()), nil
}
return 0, errors.New("invalid value type")
}
于是尝试使用cast库,将数据强制转为int类型,如下:然而还是发现有时候有有时候没有。
cast.ToInt(jsonData.Get("bid").Interface()))
但是toString是一直有值的。
cast.ToString(jsonData.Get("bid").Interface())
看了下cast.ToInt的源码。没有json.NUmber类型的转换。所以还是返回0。
func ToIntE(i interface{}) (int, error) {
i = indirect(i)
switch s := i.(type) {
case int:
return s, nil
case int64:
return int(s), nil
case int32:
return int(s), nil
case int16:
return int(s), nil
case int8:
return int(s), nil
case uint:
return int(s), nil
case uint64:
return int(s), nil
case uint32:
return int(s), nil
case uint16:
return int(s), nil
case uint8:
return int(s), nil
case float64:
return int(s), nil
case float32:
return int(s), nil
case string:
v, err := strconv.ParseInt(s, 0, 0)
if err == nil {
return int(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i)
case bool:
if s {
return 1, nil
}
return 0, nil
case nil:
return 0, nil
default:
return 0, fmt.Errorf("unable to cast %#v of type %T to int", i, i)
}
}
经过断点调试,ToString的时候,类型是fmt.Stringer 也就是任何实现了String()方法的类型都可以
func ToStringE(i interface{}) (string, error) {
i = indirectToStringerOrError(i)
switch s := i.(type) {
case string:
return s, nil
case bool:
return strconv.FormatBool(s), nil
case float64:
return strconv.FormatFloat(s, 'f', -1, 64), nil
case float32:
return strconv.FormatFloat(float64(s), 'f', -1, 32), nil
case int:
return strconv.Itoa(s), nil
case int64:
return strconv.FormatInt(s, 10), nil
case int32:
return strconv.Itoa(int(s)), nil
case int16:
return strconv.FormatInt(int64(s), 10), nil
case int8:
return strconv.FormatInt(int64(s), 10), nil
case uint:
return strconv.FormatUint(uint64(s), 10), nil
case uint64:
return strconv.FormatUint(uint64(s), 10), nil
case uint32:
return strconv.FormatUint(uint64(s), 10), nil
case uint16:
return strconv.FormatUint(uint64(s), 10), nil
case uint8:
return strconv.FormatUint(uint64(s), 10), nil
case []byte:
return string(s), nil
case template.HTML:
return string(s), nil
case template.URL:
return string(s), nil
case template.JS:
return string(s), nil
case template.CSS:
return string(s), nil
case template.HTMLAttr:
return string(s), nil
case nil:
return "", nil
case fmt.Stringer:
return s.String(), nil
case error:
return s.Error(), nil
default:
return "", fmt.Errorf("unable to cast %#v of type %T to string", i, i)
}
}
恰好json.Number类型实现了,所以他可以正常转换为String。
总结:总结:simplejson会将数字类型转换为json.Number类型,
func (j *Json) UnmarshalJSON(p []byte) error {
dec := json.NewDecoder(bytes.NewBuffer(p))
dec.UseNumber()
return dec.Decode(&j.data)
}
MustInt() 不会强转string类型的数字为int。
cast.ToInt()对json.Number类型也转换不了。。。