I'm confused about the best way to initialize a struct that contains a map. Running this code produces panic: runtime error: assignment to entry in nil map:
package main
type Vertex struct {
label string
}
type Graph struct {
connections map[Vertex][]Vertex
}
func main() {
v1 := Vertex{"v1"}
v2 := Vertex{"v2"}
g := new(Graph)
g.connections[v1] = append(g.coonections[v1], v2)
g.connections[v2] = append(g.connections[v2], v1)
}
One idea is to create a constructor, as in this answer.
Another idea is to use an add_connection method that can initialize the map if it's empty:
func (g *Graph) add_connection(v1, v2 Vertex) {
if g.connections == nil {
g.connections = make(map[Vertex][]Vertex)
}
g.connections[v1] = append(g.connections[v1], v2)
g.connections[v2] = append(g.connections[v2], v1)
}
Are there other options? Just wanted to see if there is a commonly-accepted way to do this.
I would probably use a constructor to do this:
func NewGraph() *Graph {
var g Graph
g.connections = make(map[Vertex][]Vertex)
return &g
}
I've found this example in the standard image/jpeg package (not with a map though, but with a slice):
type Alpha struct {
Pix []uint8
Stride int
Rect Rectangle
}
func NewAlpha(r Rectangle) *Alpha {
w, h := r.Dx(), r.Dy()
pix := make([]uint8, 1*w*h)
return &Alpha{pix, 1 * w, r}
}
It's very common for code (especially code fully under your control) to assume you initialize the data structure correctly. A struct literal is usually used in this case
g := &Graph{
connections: make(map[Vertex][]Vertex),
}
Composite literals work just fine inside a constructor. Contriving an example using the initial question (and naively storing copies of Vertices in the map):
func NewGraph(v1 Vertex, v2 Vertex) *Graph {
return &Graph{ map[Vertex][]Vertex{ v1: []Vertex{v2}, v2: []Vertex{v1} }}
}
func main() {
v1 := Vertex{"v1"}
v2 := Vertex{"v2"}
g := NewGraph(v1, v2)
fmt.Println(g)
}
https://play.golang.org/p/Lf4Gomp4tJ
Related
I need to have a map of string as key and unique (no dupes) int64 array as value so I decided to use something like below so that value can act as a set.
var customerCatalog = make(map[string]map[int64]bool)
Above map is populated with some data in it. Now I am trying to populate my concurrent map in golang by reading above regular customerCatalog map but I am getting error:
for k, v := range customerCatalog {
r.customerCatalog.Upsert(k, v, func(exists bool, valueInMap interface{}, newValue interface{}) interface{} {
typedNewValue := newValue.([]int64)
if !exists {
return typedNewValue
}
typedValueInMap := valueInMap.([]int64)
return append(typedValueInMap, typedNewValue...)
})
}
This is the error I am getting. I am using upsert method as shown here
panic: interface conversion: interface {} is map[int64]bool, not []int64
What is wrong I am doing?
I believe a minimal, reproducible, example of your issue would be as follows (playground):
conMap := cmap.New()
v := map[int64]bool{}
updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
_ = newValue.([]int64)
return nil
}
conMap.Upsert("foo", v, updateItemFn)
Note: I have stripped out the loop etc because that is irrelevant to the panic. However you should note that because the loop iterates over a map[string]map[int64]boolthe type of v will be map[int64]bool.
The Upsert function looks up the key in the map and then passes it and the value you passed in to the function.
So your function is receiving a map[int64]bool and the first thing it does is to assert that this is a []int64 (which will fail because it's not). To fix this you need to convert the map[int64]bool into a []int64. This could be done before calling the Upsert or within your implementation of UpsertCb as shown here (playground):
conMap := cmap.New()
conMap.Set("foo", []int64{5, 6})
v := map[int64]bool{
1: true,
}
updateItemFn := func(exist bool, valueInMap interface{}, newValue interface{}) interface{} {
m := newValue.(map[int64]bool)
a := make([]int64, 0, len(m))
for k := range m {
a = append(a, k)
}
if valueInMap == nil { // New value!
return a
} else {
typedValueInMap := valueInMap.([]int64)
return append(typedValueInMap, a...)
}
return a
}
conMap.Upsert("foo", v, updateItemFn)
fmt.Println(conMap.Get("foo"))
The above has been kept simple to demonstrate the point; in reality you may want to add all of the values into a map so as to avoid duplicates.
I have the following structure in Golang
type mystruct struct {
Name string
Power int
}
My purpose is to write a function that takes as input a slice of type *mystuct and returns a slice of type int containing the "Power" property taken from the input slice.
my code is presented below:
package main
import (
"fmt"
)
func main() {
obj := make([]*mystruct, 15)
for i, s := range obj {
s.Power = i
}
fmt.Println(extractpowers(obj))
}
func extractpowers(obj []*mystruct) []int {
powers := make([]int, len(obj))
for i, s := range obj {
powers[i] = s.Power
}
return powers
}
My issue is that the obj := make([]*mystruct, 15) creates a slices of 15 *mystruc pointers initialized to nil; which causes the code within the for loop to raise a panic of type "invalid memory or nil pointer dereference".
My question is what is the proper and fastest way to initialize the slice; (the equivalent of var lst = new List(Of mystruct) in .net)
Regards.
Use a composite literal and take its address in the loop:
for i := range obj {
obj[i] = &mystruct{Power: i}
}
Try it on the Go Playground.
For example
var myStructRef *Vertex
var myStruct Vertex
myStructRef = &Vertex{2, 3}
myStruct = Vertex{2, 3}
fmt.Println(myStructRef)
fmt.Println(myStruct)
changeByReferenceStruct(myStructRef)
changeByValueStruct(myStruct)
fmt.Println(myStructRef)
fmt.Println(myStruct)
And
func changeByValueStruct(myStruct Vertex) {
myStruct.X = 5
fmt.Println(myStruct)
}
func changeByReferenceStruct(myStruct *Vertex) {
myStruct.X = 7
fmt.Println(myStruct)
}
Isn't both myStructRef *Vertex and myStruct Vertex a pointer pointing to the struct itself? Why is there a discrepancy in behavior when I modify the struct in a function?
Is golang creating a new struct in changeByValueStruct when it resolves the parameter?
When you pass a pointer as an argument, what happens under the hood is that a copy of that pointer is created and passed to the underlying function. It should not be confused with pass-by-reference.
Let's look at an example to better grasp it:
package main
import (
"fmt"
)
type Point struct {
x int
y int
}
func (p Point) String() string {
return fmt.Sprintf("(%d, %d)", p.x, p.y)
}
func modifyValue(point Point) {
point.x += 10
}
func modifyPointer(point *Point) {
point.x = 5
point.y = 5
}
func modifyReference(point *Point) {
point = &Point{5, 5}
}
func main() {
p := Point{0, 0}
fmt.Println(p) // prints (0, 0)
modifyValue(p)
fmt.Println(p) // prints (0, 0)
modifyPointer(&p)
fmt.Println(p) // prints (5, 5)
p = Point{0, 0}
modifyReference(&p)
fmt.Println(p) // prints (0, 0)
}
What happens inside the modifyValue function is that a totally different instance of a Point structure is modified, so the value passed when calling the function is unaffected.
In the second example, a pointer to the structure is passed so the fields of the structure can be modified in a way that is visible from outside.
The most interesting point is made by the last function, modifyReference. If you are familiar with the pass by reference paradigm available in other languages you would expect to be able to modify the referenced object altogether, but this doesn't happen. It's because you're modifying a copy of the pointer passed as argument.
You may wonder, if everything is passed by value, when should you pass pointers and when values. Passing values assures the caller function that the passed structure cannot suffer any changes, so when you need this behaviour, go for the value. The downside of this is that a copy of the entire object is made and, if it is too big, memory becomes a concern.
If you're passing a big structure as an argument, using a pointer is better because it saves space, but you lose the guarantee that the object won't suffer any changes.
Passing struct to function argument makes copy of values. And passing pointer of struct doesn't. So passing struct can't update field value.
package main
import (
"fmt"
)
type Foo struct {
value int
}
func PassStruct(foo Foo) {
foo.value = 1
}
func PassStructPointer(foo *Foo) {
foo.value = 1
}
func main() {
var foo Foo
fmt.Printf("before PassStruct: %v\n", foo.value)
PassStruct(foo)
fmt.Printf("after PassStruct: %v\n", foo.value)
fmt.Printf("before PassStructPointer: %v\n", foo.value)
PassStructPointer(&foo)
fmt.Printf("after PassStructPointer: %v\n", foo.value)
}
https://play.golang.org/p/AM__JwyaJa
I have a function that has a parameter with the type interface{}. This parameter represents my template data. So on each page it stores different data types (mostly structs). I want to append some data to this parameter's data, but it's an interface{} type and I can't do it.
This is what I tried:
func LoadTemplate(templateData interface) {
appendCustomData(&templateData)
... //other functionality that is not relevant
}
func appendCustomData(dst interface{}) {
// ValueOf to enter reflect-land
dstPtrValue := reflect.ValueOf(dst)
// need the type to create a value
dstPtrType := dstPtrValue.Type()
// *T -> T, crashes if not a ptr
dstType := dstPtrType.Elem()
// the *dst in *dst = zero
dstValue := reflect.Indirect(dstPtrValue)
// the zero in *dst = zero
zeroValue := reflect.Zero(dstType)
// the = in *dst = 0
v := reflect.ValueOf(dst).Elem().Elem().FieldByName("HeaderCSS")
if v.IsValid() {
v = reflect.ValueOf("new header css value")
}
reflect.ValueOf(dst).Elem().Elem().FieldByName("HeaderCSS").Set(reflect.ValueOf(v))
//dstValue.Set(zeroValue)
fmt.Println("new dstValue: ", dstValue)
}
I can successfully get the "HeaderCSS" value. But I can't replace it with another value. What am I doing wrong?
My templateData looks like this:
I have a generic struct:
type TemplateData struct {
FooterJS template.HTML
HeaderJS template.HTML
HeaderCSS template.HTML
//and some more
}
and I have another struct, such as:
type pageStruct struct {
TemplateData //extends the previous struct
Form template.HTML
// and some other maps/string
}
I send this second struct as templateData argument.
Right now I get this error:
"reflect.Value.Set using unaddressable value" at the line: reflect.ValueOf(dst).Elem().Elem().FieldByName("HeaderCSS").Set(reflect.ValueOf(v))
The code from above is inspired from this answer: https://stackoverflow.com/a/26824071/1564840
I want to be able to append/edit values from this interface. Any idea how can I do it? Thanks.
Don't pass a pointer to interface. Instead the interface{} value should contain the pointer. And simply just hand over this interface{} value:
func LoadTemplate(templateData interface) {
appendCustomData(templateData)
... //other functionality that is not relevant
}
Even if you can't use a more concrete type than interface{} (because you must allow multiple types), you can still use type assertion, it will be "super" easy:
func appendCustomData(d interface{}) {
if ps, ok := d.(*pageStruct); ok {
ps.TemplateData.HeaderCSS += "+new"
}
}
Try this one on the Go Playground.
If you must or want to use reflection, this is how appendCustomData() can be implemented:
type Data struct {
Name string
Age int
Marks []int
}
func appendCustomData(d interface{}) {
v := reflect.ValueOf(d).Elem()
if f := v.FieldByName("Name"); f.IsValid() {
f.SetString(f.Interface().(string) + "2")
}
if f := v.FieldByName("Age"); f.IsValid() {
f.SetInt(f.Int() + 2)
}
if f := v.FieldByName("Marks"); f.IsValid() {
f.Set(reflect.ValueOf(append(f.Interface().([]int), 2)))
}
if f := v.FieldByName("Invalid"); f.IsValid() {
f.Set(reflect.ValueOf(append(f.Interface().([]int), 2)))
}
}
Testing it:
d := &Data{
Name: "Bob",
Age: 22,
Marks: []int{5, 4, 3},
}
fmt.Printf("%+v\n", d)
appendCustomData(d)
fmt.Printf("%+v\n", d)
Output (try it on the Go Playground):
&{Name:Bob Age:22 Marks:[5 4 3]}
&{Name:Bob2 Age:24 Marks:[5 4 3 2]}
Update:
To answer your edited question: there is no difference when the value passed is a struct that embeds another struct. But the value wrapped in the interface{} still must be a pointer.
Example appendCustomData() that appends content to pageStruct.TemplateData.HeaderCSS:
func appendCustomData(d interface{}) {
v := reflect.ValueOf(d).Elem()
if f := v.FieldByName("TemplateData"); f.IsValid() {
if f = f.FieldByName("HeaderCSS"); f.IsValid() {
f.Set(reflect.ValueOf(f.Interface().(template.HTML) + "+new"))
}
}
}
Testing it:
ps := &pageStruct{
TemplateData: TemplateData{
HeaderCSS: template.HTML("old"),
},
}
fmt.Printf("%+v\n", ps)
appendCustomData(ps)
fmt.Printf("%+v\n", ps)
Output (try it on the Go Playground):
&{TemplateData:{FooterJS: HeaderJS: HeaderCSS:old} Form:}
&{TemplateData:{FooterJS: HeaderJS: HeaderCSS:old+new} Form:}
I'd like to declare a map that would that would look like this, so I could map various init functions to initType:
func makeMap(){
m := make(map[initType]&InitFunc)
//How should the value declaration be set up for this map?
}
type initType int
const(
A initType = iota
B
C
D
)
func init(aInitType initType){
doStuff(aInitType)
}
func init(aInitType initType){
doOtherStuff(aInitType)
}
func init(aInitType initType){
doMoreStuff(aInitType)
}
How do I declare the function pointer type (which I called &InitFunc in the example because I don't know how to do it) so I can use it as the value in a Map?
Unlike C, you don't actually need a "pointer" to the function, since in Go, functions are reference types, similar to slices, maps, and channels. Further, the address operator, &, produces a pointer to a value, but to declare a pointer type, use *.
You seem to be wanting your InitFunc to take a single InitType and return no values. In that case, you would declare it as:
type InitFunc func(initType)
Now, your map initialization can simply look like:
m := make(map[initType]InitFunc)
A complete example would be (http://play.golang.org/p/tbOHM3GKeC):
package main
import "fmt"
type InitFunc func(initType)
type initType int
const (
A initType = iota
B
C
D
MaxInitType
)
func Init1(t initType) {
fmt.Println("Init1 called with type", t)
}
var initFuncs = map[initType]InitFunc{
A: Init1,
}
func init() {
for t := A; t < MaxInitType; t++ {
f, ok := initFuncs[t]
if ok {
f(t)
} else {
fmt.Println("No function defined for type", t)
}
}
}
func main() {
fmt.Println("main called")
}
Here, it's looping through each initType, and calling the applicable function, if it is defined.