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?
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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With