0

When unmarshalling json into a struct, I'd like to look at the struct (or any other meta data vehicle) to know the whether a json value was provided in the json input or if a json value was omitted from the json input. Consider this code as an example:

package main
import (
  "encoding/json"
  "log"
)

type Person struct {
  Name string `json:"name"`
  Grades []Grade `json:"grades"`
}

type Grade struct {
  Year int `json:"year"`
  Grade int `json:"grade"`
}

func main() {
  jsonString := `{"name":"john","grades":[{"year":1998,"grade":0},{"year":1999}]}`

  person := Person{}
  _ = json.Unmarshal([]byte(jsonString),&person)

  log.Println(person)
}

The log prints {john [{1998 0} {1999 0}]}. What is idiomatic way in Go to know that the zero of 1998 0 was explicitly declared in the JSON string while the zero of 1999 0 was the default zero when initializing the struct Grade?

The reason I want to know this difference is because I want to use this struct to create an SQL statement that updates the table field t_grade.grade = ? if and only if the zero was explicitly provided by the json string. Also note that t_grade.grade in the database is not-nullable.

I am currently using a hack where my grade struct looks like this:

type Grade struct {
  Year *int `json:"year"`
  Grade *int `json:"grade"`
}

So if the JSON string does not provide a value, then the grade field will be null. Otherwise, the grade field will hold a pointer to a value.

But I'm sure there's a better and idiomatic way to do this?

John
  • 32,403
  • 80
  • 251
  • 422
  • If the zero value is a valid / useful value, use a pointer to the type. `nil` pointer value will denote the missing case, and a non-`nil` value pointing to the zero value will denote the "present" zero value. Using a non-pointer type, you can't differentiate a missing value from a present zero value (see [Default struct values](https://stackoverflow.com/questions/40970422/default-struct-values/40970490#40970490)). – icza Sep 30 '18 at 21:11
  • ok thanks, that's the hack i mentioned in my question, was really hoping to avoid it – John Sep 30 '18 at 21:13
  • 1
    There is no easier way, see my edited comment. You could create your own `NullString` type and implement custom marshaling / unmarshaling on it, but that wouldn't be easier to read or use imo. – icza Sep 30 '18 at 21:14

0 Answers0