首页 >后端开发 >Golang >IntTo Float64 JSON转换之谜

IntTo Float64 JSON转换之谜

WBOY
WBOY原创
2024-09-03 13:20:191164浏览

The Mystery Of JSON Conversion Of IntTo Float64

Working with JSON can sound simple & clear, you have some struct, you can change it to JSON — A general unified language & back to your struct. Simple right? ?

Well, yeah, but that's until you encounter some weird behavior from the Marshal / Unmarshal functions.

Problem ?

It all started when I was trying to read the encoded payload from a JWT token, below is an example that demonstrates the issue

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    ID      int64   `json:"id"`
    PostIDs []int64 `json:"post_ids"`
}

func main() {
    u := User{
        ID:      1,
        PostIDs: []int64{1, 2, 3},
    }

    b, err := json.Marshal(u)
    if err != nil {
        panic(err)
    }

    m := make(map[string]interface{})
    if err = json.Unmarshal(b, &m); err != nil {
        panic(err)
    }

    userID, ok := m["id"].(int64)
    fmt.Printf("id: %d\nOk:%t\n", userID, ok)

    fmt.Println() // spliter

    postIDs, ok := m["id"].([]int64)
    fmt.Printf("post_ids: %v\nOk:%t\n", postIDs, ok)
}

Just marshaling and unmarshaling back out struct, so it's expected to return the same value!

Unfortunately, this didn't happen, the code above outputs

// Result
id: 0
Ok:false

post_ids: []
Ok:false

Once I saw that output, I ? the issue might be with type conversions, so I went to check what types does these interfaces have

    fmt.Printf("id: %T\n", m["id"])
    fmt.Printf("post_ids: %T\n", m["post_ids"])
// Result
id: float64
post_ids: []interface {}

So as we can see, JSON has parsed out int64 as float64, which lead to issues upon reading the data.

There is actually 2 ways to fix this issue

? Solution 01 (Hard way)

Use type assertions of float64, Notice that []interface{} can't be mapped right away to []float64, so we have to iterate each element and convert it

        // Parse UserID
    userID, _ := m["id"].(float64)
    fmt.Printf("id: %f\n", userID)

    fmt.Println() // spliter

    // Parse PostIDs
    postIDsArr, _ := m["post_ids"].([]interface{})
    postIDs := make([]int64, len(postIDsArr))
    for i, v := range postIDsArr {
        id, _ := v.(float64) // NOTICE: direct conversion to int64 won't work here!
        postIDs[i] = int64(id)
    }

    fmt.Printf("post_ids: %v\n", postIDs)
// Result
id: 1.000000

post_ids: [1 2 3]

? Solution 02 (Easy way)

Parse it back to a struct

    b, err = json.Marshal(m) // m = map[string]interface{}
    if err != nil {
        panic(err)
    }

    var u2 User
    if err := json.Unmarshal(b, &u2); err != nil {
        panic(err)
    }

    fmt.Println(u2.ID)
    fmt.Println(u2.PostIDs)

Of course, you might think, why should we even use Solution 01, isn't Solution 02 better?

Well it depends, you don't always want to create a struct to read a single attribute from a struct, so the correct answer is -- It depends!

I think that's all for today's article, wish you learned something new, my fellow gopher ?.

以上是IntTo Float64 JSON转换之谜的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn