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.
Related
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{}.
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.
What is the idiomatic way to deal with unsized arrays in Go? I'm working on the ETW wrappers and the TdhGetEventInformation function fills in the provided memory buffer with event information. The event metadata is represented by TRACE_EVENT_INFO structure, which has an array member declared as:
EVENT_PROPERTY_INFO EventPropertyInfoArray[ANYSIZE_ARRAY];
I'm calling the TdhGetEventInformation function in a way that the provided buffer has enough space to populate event properties array:
var bufferSize uint32 = 4096
buffer := make([]byte, bufferSize)
tdhGetEventInformation.Call(
uintptr(unsafe.Pointer(eventRecord)),
0, 0,
uintptr(unsafe.Pointer(&buffer[0])),
uintptr(unsafe.Pointer(&bufferSize)),
)
However, since I'm tempting to model the Go counterpart struct with EventPropertyInfoArray field as
EventPropertyInfoArray [1]EventPropertyInfo
the compiler is not able to re dimension the array according to the number of available properties for each event, so I end up with one-array item.
Do you have any smart ideas on how handle this edge case?
Thanks in advance
So you want a variable sized array in Go? Use a slice?
EventPropertyInfoArray [1]EventPropertyInfo
Would be
EventPropertyInfoArray []EventPropertyInfo
If you have a rough idea of a maximum it could hold you could make an array using make something like this, but this wouldn't help you out in declaring a struct:
EventPropertyInfoArray = make([]EventPropertyInfo, len, capacity)
After lots of trial and error, I managed to get the right slice from the backing array through standard technique for turning arrays into slices:
properties := (*[1 << 30]EventPropertyInfo)(unsafe.Pointer(&trace.EventPropertyInfoArray[0]))[:trace.PropertyCount:trace.PropertyCount]
I get cannot use map[string]MyType literal (type map[string]MyType) as type map[string]IterableWithID in argument to MapToList with the code below, how do I pass in a concrete map type to method that expects a interface type?
https://play.golang.org/p/G7VzMwrRRw
Go's interface convention doesn't quite work the same way as in, say, Java (and the designers apparently didn't like the idea of getters and setters very much :-/ ). So you've got two core problems:
A map[string]Foo is not the same as a map[string]Bar, even if Bar implements Foo, so you have to break it out a bit (use make() beforehand, then assign in a single assignment).
Interface methods are called by value with no pointers, so you really need to do foo = foo.Method(bar) in your callers or get really pointer-happy to implement something like this.
What you can do to more-or-less simulate what you want:
type IterableWithID interface {
SetID(id string) IterableWithID // use as foo = foo.SetID(bar)
}
func (t MyType) SetID(id string) IterableWithID {
t.ID = id
return t
}
...and to deal with the typing problem
t := make(map[string]IterableWithID)
t["foo"] = MyType{}
MapToList(t) // This is a map[string]IterableWithID, so compiler's happy.
...and finally...
value = value.SetID(key) // We set back the copy of the value we mutated
The final value= deals with the fact that the method gets a fresh copy of the value object, so the original would be untouched by your method (the change would simply vanish).
Updated code on the Go Playground
...but it's not particularly idiomatic Go--they really want you to just reference struct members rather than use Java-style mutators in interfaces (though TBH I'm not so keen on that little detail--mutators are supes handy to do validation).
You can't do what you want to do because the two map types are different. It doesn't matter that the element type of one is a type that implements the interface which is the element type of the other. The map type that you pass into the function has to be map[string]IterableWithID. You could create a map of that type, assign values of type MyType to the map, and pass that to the function.
See https://play.golang.org/p/NfsTlunHkW
Also, you probably don't want to be returning a pointer to a slice in MapToList. Just return the slice itself. A slice contains a reference to the underlying array.
http://golang.org/pkg/sort/
This is from Go example.
// OrderedBy returns a Sorter that sorts using the less functions, in order.
// Call its Sort method to sort the data.
func OrderedBy(less ...lessFunc) *multiSorter {
return &multiSorter{
changes: changes,
less: less,
}
}
What does this do by colon? Is it mapping? Is it closure? Too much new syntax here. What should I read to understand this syntax in Go?
It's a factory function, creating and initialising a struct of type multisorter:
https://sites.google.com/site/gopatterns/object-oriented/constructors
Additionally, Go "constructors" can be written succinctly using initializers within a factory function:
function NewMatrix(rows, cols, int) *matrix {
return &matrix{rows, cols, make([]float, rows*cols)}
}
Also, it is using named parameters when initialising:
http://www.golang-book.com/9
This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (Circle) More often we want to give each of the fields a value. We can do this in two ways. Like this:
c := Circle{x: 0, y: 0, r: 5}
The `less ...lessFunc` in the func declaration means:
any number of parameters, each of type `lessFunc` can be passed here, and will be stored in the slice `less`
So it creates a `multiSorter` struct, which supports the sort interface, and calling the sort method from that interface (and implemented by multiSorter) will cause the object to use each lessFunc in turn while sorting
Does this make sense? I can expand more if needed...