The Mystery Of JSON Conversion Of IntTo Float64

WBOY
Release: 2024-09-03 13:20:19
Original
1107 people have browsed it

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)
}
Copy after login

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
Copy after login

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"])
Copy after login
// Result
id: float64
post_ids: []interface {}
Copy after login

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)
Copy after login
// Result
id: 1.000000

post_ids: [1 2 3]
Copy after login

? 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)
Copy after login

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!

source:dev.to
Statement of this Website
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
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!