Home  >  Article  >  Backend Development  >  The Mystery Of JSON Conversion Of IntTo Float64

The Mystery Of JSON Conversion Of IntTo Float64

WBOY
WBOYOriginal
2024-09-03 13:20:191061browse

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 ?.

The above is the detailed content of The Mystery Of JSON Conversion Of IntTo Float64. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn