How to set value array of struct with pointer in Go - go

I have an array of Struct that contains a pointer, i want to set this with some data but when it exit the for loop the value will return nil
heres example :
https://go.dev/play/p/iCiHsVfJkMx
Is there any way to return with complete data, I mean with value on it

You are ranging over t which is of type []Data. Data is not a pointer type, so v will be set to a copy of t[0], then t[1], etc.
You need to access the struct via array index such that there is an intact chain of references.
https://go.dev/play/p/BqgavPfx16V

Another way to fix your issue is to use Data{new(UserData)} instead of Data{}.

Related

How to append to slices as map values with reflection?

Assumptions
I'm using go1.17 not 1.18 so answers in go 1.18 may help others but not me.
I searched and tried many things but this scenario never solved.
Problem
import (
"fmt"
"reflect"
)
func main() {
l := map[string][]interface{}{"a": {}}
appendData(l["a"])
fmt.Println(l["a"])
}
func appendData(k interface{}) {
lValue := reflect.ValueOf(k)
lValue.Set(reflect.Append(lValue, reflect.ValueOf(1)))
lValue.Set(reflect.Append(lValue, reflect.ValueOf(2)))
lValue.Set(reflect.Append(lValue, reflect.ValueOf(3)))
}
I simplified the scenario into this piece of code.
I just need to have the ability to change elements of that passed slice of interfaces([]interface{}) from appendData function.
Please do not send me this line of code l["a"] = appendData(l["a"]).([]interface{}).
I know that this works but I can't implement that in my code for some reason.(I'm doing some BFS stuff and I can't do this, I have to change some values at the time)
What I Want?
I just wanna see this output:
[1, 2, 3]
Is it possible?
Are there any other alternative ways that I can change those data from somewhere else in my code?
Thanks for your help.
You will never see [1, 2, 3] printed, no matter what appendData() does if only the slice is passed.
2 things: You can't change values stored in maps. If the value must be changed, you have to reassign the new value. For details see How to update map values in Go
Second: you also can't change values stored in interfaces. For details, see Removing an element from a type asserted Slice of interfaces
The right approach: if you want to change something, always pass a pointer to it, and modify the pointed value. Of course in your case you can't pass a pointer that points to a value stored in a map (that "points into the map"), so that's not possible. Map index expressions are not addressable, for details, see Cannot take the address of map element. If you must use a map, you must store a pointer in the map, and you may pass that pointer.
Another approach is to return the new, modified slice and assign the new slice at the caller, exactly what / how the builtin append() does it (append() returns a new slice which you're expected to assign / store). If you go down this route, you may store non-pointer slices in the map, since you can reassign the modified slice to the same map key.

How to obtain the address of an object referenced by an interface

I have two interface objects which I would like to compare against each other. I don't only want to compare if their values are the same, I also want to know whether these two interfaces are referencing the same object or if they're referencing two different objects with equal values.
Is there some way to extract the address an interface references from an interface object? Then I could just compare the two addresses to know whether the two interfaces reference the same object.
If two interfaces have pointer values, then you can simply compare them:
func cmp(v1, v2 interface{}) bool {
return v1==v2
}
func main() {
a:=1
b:=1
c:=&a
cmp(&a,&b) // false
cmp(a, b) // true, compare values
cmp(c, &a) // true
}
Be careful here.
Two different interface values can never "reference" the "same object" as an interface value always contains a copy of the value you wrap in the interface value. Variable identity (your "same object") would be "equal address" which is undefined for values wrapped in an interface value as these wrapped values are not addressable. So a clear no to your question.
But of course you can store a pointer to your value in the interface value iff the pointer type satisfies the interface.
It is best avoided to talk about "object" and "reference". Go has values of certain types. Some values are addressable. You can store addresses of addressable values in appropriately typed pointer variables.

Getting error while access the struct type of array element as undefined (type []ParentIDInfo has no field or method PCOrderID)

I am new to golang and I have one issue which I think community can help me to solve it.
I have one data structure like below
type ParentIDInfo struct {
PCOrderID string `json:"PCorderId",omitempty"`
TableVarieties TableVarietyDC `json:"tableVariety",omitempty"`
ProduceID string `json:"PRID",omitempty"`
}
type PCDCOrderAsset struct {
PcID string `json:"PCID",omitempty"`
DcID string `json:"DCID",omitempty"`
RequiredDate string `json:"requiredDate",omitempty"`
Qty uint64 `json:"QTY",omitempty"`
OrderID string `json:"ORDERID",omitempty"`
Status string `json:"STATUS",omitempty"`
Produce string `json:"Produce",omitempty"`
Variety string `json:"VARIETY",omitempty"`
Transports []TransportaionPCDC `json:"Transportaion",omitempty"`
ParentInfo []ParentIDInfo `json:"ParentInfo",omitempty"`
So I have issue to access the PCOrderID which inside the []ParentIDInfo . I have tried below however I getting error as "pcdcorder.ParentInfo.PCOrderID undefined (type []ParentIDInfo has no field or method PCOrderID)"
keyfarmercas = append(keyfarmercas, pcdcorder.ParentInfo.PCOrderID)
Any help will be very good
Thanks in advance
PCDCOrderAsset.ParentInfo is not a struct, it does not have a PCOrderID field. It's a slice (of element type ParentIDInfo), so its elements do, e.g. pcdcorder.ParentInfo[0].PCOrderID.
Whether this is what you want we can't tell. pcdcorder.ParentInfo[0].PCOrderID gives you the PCOrderID field of the first element of the slice. Based on your question this may or may not be what you want. You may want to append all IDs (one from each element). Also note that if the slice is empty (its length is 0), then pcdcorder.ParentInfo[0] would result in a runtime panic. You could avoid that by first checking its length and only index it if its not empty.
In case you'd want to add ids of all elements, you could use a for loop to do that, e.g.:
for i := range pcdorder.ParentInfo {
keyfarmercas = append(keyfarmercas, pcdcorder.ParentInfo[i].PCOrderID)
}

If a function copies an element of a slice to a variable, is it working with a pointer to that element or a copy?

Example situation:
There's a global struct holding a slice of structs.
type stctUser struct {
user string
privilege int
created time.Time
}
type stctAllUsers struct {
sync.RWMutex
slcUsers []stctUser
}
var strctAllUsers stctAllUsers
There's a function that wants to operate on the users, and to reduce the time it's locking that global struct, I want to grab a user and release the lock
var strctUserTemp stctUser
strctAllUsers.RLock
for a := range strctAllUsers.slcUsers {
if tmpName == strctAllUsers.slcUsers[a].user {
strctUserTemp = strctAllUsers.slcUsers[a]
break
}
}
strctAllUsers.RUnlock
Is strctUserTemp working with a separate copy of slcUsers[a], or is it a pointer to that element of the slice? For example, strctAllUsers.slcUsers[a] is "Tom" and changing strctUserTemp.user = "Bob", would strctAllUsers.slcUsers[a] still be Tom?
(Before, it seems that making a copy of a slice to a new variable would mean changes to that new variable slice could change the original...so it assigned a pointer instead of creating a copy. Or am I misremembering?)
Update: Seeing as I was too stupid to take five minutes to test this out...here's a link to the behavior that had me questioning this in the first place, and I wanted to clarify the implementation before assuming I understood what was happening and creating a bug in the actual stuff I was working on. https://play.golang.org/p/ndmJ0h1z-sT
Most importantly: assignment always copies. However, it could be a copy of a pointer.
There are three basic scenarios:
You have a slice of values. You assign an element from the slice to a local variable, creating a copy of the value. There is no connection between the local variable and the slice element.
You have a slice of pointers. You assign an element from the slice to a local variable, creating a copy of the pointer. Changes to the pointed-to value will be reflected in any other use of the slice element, because the local pointer and the pointer in the slice point to the same memory.
You have a slice of values. You assign a reference to an element from the slice to a local variable (e.g. myVar := &mySlice[0]). The local variable contains a copy of the reference created by the addressing expression. Changes to the local variable's value are reflected by any other use of the slice element, because the local pointer points directly to the memory where that slice element is held.
Note that the last option means you'll have a fragile pointer - if you append to the slice and the underlying array moves around in memory you'll get some confusing behavior.

How to insert a struct with nil field to mongo?

I am trying to insert a struct to mongo. Firstly I get the data from an API as JSON and assign the data to a struct. Some fields might be nil. After that I insert the struct to mongoDB. So the problem I get is that when inserted, all the fields are initialized. For example I have a struct like this:
type VirtualMachine struct {
VirtualMachineID utils.SUUID `bson:"VirtualMachineID"`
Cdroms []*VM.VirtualMachineCdrom `bson:"Cdroms"`
CpuAllocatedMHz int `bson:"CpuAllocatedMHz"`
Name string `bson:"Name"`
}
If I get Json data like this
{
"VirtualMachineID":'16as4df663a',
"Cdroms":null,
"CpuAllocatedMHz":1666,
"Name":'VMName'
}
after I put it to mongo, the null field becomes an empty array. I need to avoid that. 'omitempty' did not help because it skips the field as well if the provided field happens to be an empty array and not null.
Firstly I thought it was because of the pointers, but later I found that the same happens to all data types. Shortly, if its nil, mgo converts it to its zero value.
I think I am missing something here, because it would be weird if mgo converts all nil values to their zero values by design.
Try *[]*VM.VirtualMachineCdrom (or just *[]VM.VirtualMachineCdrom if you don't actually need the elements to be pointers). A nil slice == a zero length slice, but a nil pointer to a slice does not.

Resources