-1

Recently, I got exposed to following source code from "Go Programming Blueprints" book.

type googleGeometry stuct {
    *googleLocation `json:"location"`
}
type googleLocation struct {
    Lat float64 `json:"lat"`
    Lng float64 `json:"lng"`
}

What I don't understand is why googleGeometry structure uses pointer instead of literal, and what is the reason behind such declaration?

I would expect below declaration instead of a pointer.

type googleGeometry stuct {
    gl googleLocation `json:"location"`
}
2
  • That is an embedded type, not a struct member. There is a distinction there, but I'm still not clear why they chose a pointer rather than a plain struct in this case. Commented Jul 28, 2017 at 13:19
  • @captncraig it's still a struct member; an embedded type is a kind of struct member. Commented Jul 28, 2017 at 13:37

4 Answers 4

2

I suppose it is because location can be null or would be absent at all.
Such cases can be represented with pointers. Because if it would be literal you will always have default values for lat and lng.
Please take a look on this example: Why pointer?

And this with a value type instead of reference: Value types always have default values

Sign up to request clarification or add additional context in comments.

1 Comment

Yeah, it seems strange on a struct that doesn't contain anything else, but I did a struct with several embedded pointers recently to control which groups of fields did and didn't appear in JSON output. Perhaps they're doing that elsewhere in this library, and this one is just for consistency? Or perhaps they really just do want to serialize {} sometimes.
1

googleGeometry embeds a pointer to a googleLocation. It is essentially an unnamed field so that the Lat and Lng fields are accessible as if they were top level fields.

Why use

type googleGeometry stuct {
    *googleLocation `json:"location"`
}

instead of

type googleGeometry stuct {
    googleLocation `json:"location"`
}

?

I think they made the wrong call here. The pointer is nillable so if you do:

g := googleGeometry{}
fmt.Println(g.Lat)

you will get a nil reference panic. If you embed a non-pointer struct, the fields will be automatically initialized to zeros.

2 Comments

On top of that, nil pointers will not be marshalled to JSON. Otherwise you could end up with "location": ""
Haven't read the book, but it could be that *googleLocation implents some interface that they want googleGeometry to implement as well by using composition, embedding googleLocation would not work, just my 2c.
1

I'm not sure about the entire context of the question, however when a pointer is embedded inside the struct, even when the variable of type googleGeometry is passed by value the embedded googleLocation pointer still points to the same memory address as the initial variable (as the address is simply copied). Therefore although the original struct is passed by value both original and the copied variables share the same embedded pointer. That might be the intended behaviour.

Comments

1

The main reason is JSON (de)serialization. If you want to unmarshal JSON into a struct and validate if certain attributes are present in the document using a pointer is a convenient way. Since the unmarshaller will leave missing fields nil.

The following code code will print: missing location attribute

func main() {
    doc := []byte("{}") // json that misses a location member

    var geometry googleGeometry
    json.Unmarshal(doc, &geometry)

    if geometry.googleLocation == nil {
        fmt.Println("missing location attribute")
    } else {
        fmt.Println("location attribute unmarshalled correctly")
    }
}

See: https://play.golang.org/p/hTj5HvI-AE

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.