Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Go correctly marshal float64 to JSON?

Using go1.1.2 Win64, I have a Go program that "marshal"'s a struct containing a float64. When the value of the float64 is not a whole number eg. 1234.44, then it gets "marshal"ed as a float (json.Marshal). When however it is a whole number eg. "1234.00" it is marshalled as an integer"1234". When I receive that at the other end (Dart), Dart (30188) treats the whole number as an integer (in map - JSON.decode). Consequently the Dart program aborts when the representation of the float (double) data doesn't contain a decimal point, and I attempt to "extract" it from the map as a double.

This can obviously be solved a number of different ways (eg. convert to integer and then convert back to float), however I wondered if there is another (better) way to handle this situation.

Is there another better way to handle this than to convert float64 to integer?

like image 306
Brian Oh Avatar asked Nov 20 '13 14:11

Brian Oh


People also ask

What is Golang JSON marshal?

The Go standard library offers a package that has all you need to perform JSON encoding and decoding. The encoding/json package. It allows you to do encoding of JSON data as defined in the RFC 7159. When working with data we usually want to encode some Go struct into a json string.

What is JSON marshalling and Unmarshalling?

Generally, encoding/decoding JSON refers to the process of actually reading/writing the character data to a string or binary form. Marshaling/Unmarshaling refers to the process of mapping JSON types from and to Go data types and primitives.

How does JSON Unmarshal work in Golang?

To parse JSON, we use the Unmarshal() function in package encoding/json to unpack or decode the data from JSON to a struct. Unmarshal parses the JSON-encoded data and stores the result in the value pointed to by v. Note: If v is nil or not a pointer, Unmarshal returns an InvalidUnmarshalError.

How do I declare JSON in Golang?

Go encode to JSONWe declare the User struct. We create the struct instance. We encode the u1 struct into JSON with Marshal . Since json_data is a byte array, we convert it to a string with the string function.


2 Answers

The following appears to be (to me) the solution. The integer method toDouble() also works with "num" (or vice versa). It appears to me that when working with json and monetary values that could be interpreted as either double or int by Dart, that it is necessary to use "as num" and then use the built-in method toDouble().

Example (Go):

type cuAcctRow struct {
         .....
    D_AcctBal    float64
         .....
}
    if baJsAcctDet, oOsError = json.Marshal(uAcctRow); oOsError != nil {

Example (Dart):

Map mAcctData = json.parse(sResponse);

double dAcctBal  = (mAcctData['D_AcctBal'] as num).toDouble();

I don't know why Dart doesn't allow direct assignment of integer to double, but I'm sure there is a good reason.

like image 53
Brian Oh Avatar answered Sep 22 '22 23:09

Brian Oh


JSON, just like Javascript, doesn't differ between integers and numbers.

If Dart treats 1234.00 differently from 1234, then it is making assumptions about the value not supported by the JSON specification.

While Go does indeed marshal float64 correctly, one way of getting around the problem with Dart's assumption is by implementing the Marshaler interface on your own type:

type Number float64

func (n Number) MarshalJSON() ([]byte, error) {
    // There are probably better ways to do it. It is just an example
    return []byte(fmt.Sprintf("%f", n)), nil
}

And then you can use your own Number type, instead of float64, in the structs that you will Marshal. This way you can make sure that your numbers will always be marshaled with a decimal point.

Working example on Playground

like image 37
ANisus Avatar answered Sep 20 '22 23:09

ANisus