Pointer within a custom structure - go

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"`
}

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

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

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.

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.

Related

Why can't I use an empty interface that holds a concrete type of string as a return value in a function declared to return string?

I am a newcomer of go and recently I am following the instruction of A Tour of Go.
I am reading the chapter on Interface and I am really confused by the concept.
The code is as follows
package main
import "fmt"
func main() {
testTypeAssertion()
}
func testTypeAssertion() string {
var i interface{}="hello"
fmt.Printf("type of i is %T",i)
return i
// return "hello"
}
In this case, it will cause error
# example
./prog.go:12:2: cannot use i (type interface {}) as type string in return argument: need type assertion
But if I comment return i and uncomment return "hello", it goes like this
type of i is string
So why exactly do we need a type assertion here?
What's the type of i exactly?
I believe this question is different from cannot use type interface {} as type person in assignment: need type assertion. Because in that question the poster is trying to assign an empty interface value to a variable that has a concrete self-defined type person. In my question, I am trying to figure out why an interface holding a concrete string value cannot be a return value of a function whose return value type is exactly string.
Thanks to mkopriva's answer in the comment section and bugstop's answer. I will accept that it's caused by the different usage of static type and dynamic type. By the way, Reality's answer is very interesting and really helped me to understand the whole concept!
Think of an interface as a little box that holds a type and a value. The box has methods that map to methods on the value in the box.
The statement fmt.Printf("type of i is %T",i) prints the type in the box, not the type of the box itself. Reflect package trickery is required to print the type of i. but that's outside the scope of this question.
The statement return i does not compile because interface{} is not a string. The box contains a string, but the box is not a string.
We can get the value out of the box using a type assertion: return i.(string). This statement panics if i does not contain a string.
it's an interface value i with a dynamic type string.
It may be useful to read about:
How to determine an interface{} value's "real" type?
Interfaces in Go
The variable i is of type interface{}, and its value is the string "hello". An interface is simply a method-set, and since interface{} has no methods specified, all types satisfy it. Because of this, the assignment i="hello" works.
However, you cannot return an interface{} where a string is required, because string is not the same type as an interface{}. You could have returned a string where an interface{} is required, because a string implements interface{}.

how to create a function parameter that won't be copied and cannot be null

In golang, Is it possible to create a function that takes a struct with the following constraints:
the struct must not be copied (its relatively big)
the caller must not be able to pass nil
EDIT:
I tried using pointers but that can be set to null. I can't find any good articles on how to use references and it doesn't seem like I can pass by reference.
You can create tiny struct wrapper which holds private pointer to big struct and defines Get method to allow acquisition of this big struct. Inside Get you check if pointer is nil then it panics.
Something like:
type StructHolder struct {
target *BigStruct
}
func (s StructHolder) Get() *BigStruct {
if s.target == nil {
panic("target is nil")
}
return s.target
}
Why would you do this? I'd think its better to pass a pointer and check its value.

Cannot use as type in assignment in go

when I compile my code, I get the following error message, not sure why it happens. Can someone help me point why? Thank you in advance.
cannot use px.InitializePaxosInstance(val) (type PaxosInstance) as
type *PaxosInstance in assignment
type Paxos struct {
instance map[int]*PaxosInstance
}
type PaxosInstance struct {
value interface{}
decided bool
}
func (px *Paxos) InitializePaxosInstance(val interface{}) PaxosInstance {
return PaxosInstance {decided:false, value: val}
}
func (px *Paxos) PartAProcess(seq int, val interface{}) error {
px.instance[seq] = px.InitializePaxosInstance(val)
return nil
}
Your map is expecting a pointer to a PaxosInstance (*PaxosInstance), but you are passing a struct value to it. Change your Initialize function to return a pointer.
func (px *Paxos) InitializePaxosInstance(val interface{}) *PaxosInstance {
return &PaxosInstance {decided:false, value: val}
}
Now it returns a pointer. You can take the pointer of a variable using & and, should you need the struct value itself, dereference it again with *.
After a line like
x := &PaxosInstance{}
or
p := PaxosInstance{}
x := &p
the value type of x is *PaxosInstance. And if you ever need to, you can dereference it back into a PaxosInstance struct value with
p = *x
You usually do not want to pass structs around as actual values, because Go is pass-by-value, which means it will copy the whole thing. Using struct values with maps and slices often results in logic errors because a copy is made should you iterate them or otherwise reference them except via index. It depends on your use-case, but your identifier Instance would infer that you would want to avoid duplications and such logic errors.
As for reading the compiler errors, you can see what it was telling you. The type PaxosInstance and type *PaxosInstance are not the same.
The instance field within the Paxos struct is a map of integer keys to pointers to PaxosInstance structs.
When you call:
px.instance[seq] = px.InitializePaxosInstance(val)
You're attempting to assign a concrete (not pointer) PaxosInstance struct into an element of px.instance, which are pointers.
You can alleviate this by returning a pointer to a PaxosInstance in InitializePaxosInstance, like so:
func (px *Paxos) InitializePaxosInstance(val interface{}) *PaxosInstance {
return &PaxosInstance{decided: false, value: val}
}
or you could modify the instance field within the Paxos struct to not be a map of pointers:
type Paxos struct {
instance map[int]PaxosInstance
}
Which option you choose is up to your use case.
For anyone else pulling their hair out: check your imports.
Not sure when it started happening, but my Visual Studio Code + gopls setup will occasionally insert an import line that references my vendored dependencies path instead of the original import path. I usually won't catch this until I start polishing code for release, or an error like this one pops up.
In my case this caused two otherwise identical types to not compare equally. Once I fixed my imports this resolved the error.

unmarshalling generic json with a type lookup map

I'm following up on Golang Decoding Generic JSON Objects to One of Many Formats as a way to unmarshal generic json. I'm going to have a multitude of different types tho which can be added by others, so hardcoding case statements is not feasible.
I also don't want to hardcode the type as a string, but let the ones using the library chose the "lookup" name, in case they want to rename their underlying structs later.
I am basically looking for something like this:
type myInterface interface {
Something() // irrelevant, just to show you It's not about interface{}
}
type myBar struct {} // fulfils myInterface
type mySomething struct {} // fulfils myInterface
var types = make(map[string]type) // <--- Obvious Pseudo code ;)
types["foo:bar"] = myBar // done by whoever uses the library
types["1230988"] = mySomething // ...
type storageWrapper struct {
Type string
Data json.RawMessage
}
func loadSomething(id string) myInterface {
buf := db.load(id) // pseudo code but you get the idea
sw := &storageWrapper{}
json.Unmarshal(buf, sw)
// now the interesting part
targetType := types[sw.Type]
thing := &targetType{}
json.Unmarshal(sw.Data, thing)
return thing
}
I have this feeling that I'm overthinking the whole Problem. Or that I'm trying to bend Go into something that conflicts with its underlying philosophy. I'm very open and thankful for any advice that suggests a different approach to the whole Problem
Have types be a map[string]myInterface, and to register a type, have callers store an empty value of that type (not a reference) into the map. Then, to unmarshal, you can "get the type" by copying the empty value out of the map, unmarshaling into it, and returning it (or a reference to it). The interface value will do the job of identifying which type is wanted. Plus, if users want to default some fields to non-zero/empty values in case they're not provided in the JSON, they can actually do that by storing those values within the struct in the type map.

Nested properties for structs with unknown property names?

I'm using JSON to get some values into a variable from an external source.
I have a type like this that json.Unmarshal puts values into:
type Frame struct {
Type string
Value map[string]interface{}
}
var data Frame
After unmarshal, I can access a the type by: data.Type
but if I try doing something like:
if data.Type == "image" {
fmt.Printf("%s\n", data.Value.Imagedata)
}
The compiler complains about no such value data.Value.Imagedata.
So my question is, how do I reference properties in Go that I know will be there depending on some condition?
Doing this works:
type Image struct {
Filename string
}
type Frame struct {
Type string
Value map[string]interface{}
}
But that isn't very flexible as I will be receiving different Values.
json.Unmarshal will do its best to place the data where it best aligns with your type. Technically your first example will work, but you are trying to access the Value field with dot notation, even though you declared it to be a map:
This should give you some form of output:
if data.Type == 'image'{
fmt.Printf("%v\n", data.Value["Imagedata"])
}
… considering that "Imagedata" was a key in the JSON.
You have the option of defining the type as deeply as you want or expect the structure to be, or using an interface{} and then doing type assertions on the values. With the Value field being a map, you would always access the keys like Value[key], and the value of that map entry is an interface{} which you could type assert like Value[key].(float64).
As for doing more explicit structures, I have found that you could either break up the objects into their own types, or define it nested in one place:
Nested (with anonymous struct)
type Frame struct {
Type string
Value struct {
Imagedata string `json:"image_data"`
}
}
Seperate structs
type Frame struct {
Type string
Value value
}
type value struct {
Imagedata string `json:"image_data"`
}
I'm still learning Go myself, so this the extent of my current understanding :-).

Resources