Golang fill slice in function not working - go

I am trying to add stuff to my slice but somehow the slice is never updated.
endpointsList := make([]string, 3)
for _, route := range routes {
if len(route.Endpoints) > 0 {
waitGroup.Add(1)
go endpointRoutine(route, template, route.Protected, &waitGroup, &endpointsList)
}
}
I pass the endpointsList by reference, meaning I should be able to assign new things to its memory location I think.
In the function endpointRoutine I do this:
list := make([]string, 3)
for _, r := range route.Endpoints {
list = append(list, "some data comes here...")
}
endpointsList = &list
When I do a printr after this (below my first bit of code and AFTER the waitGroup.Wait() part) the slice is still empty.
Obviously, I am overwriting the slice now and my final goal is to ADD to the slice. But when I try to add with this code:
endpointsList = append(endpointsList, "fdssdfsdfsdf")
It gives me the error:
cannot use endpointsList (type *[]string) as []Type
Can someone please explain to me what might be wrong?

With endpointsList = &list, you are assigning the pointer pointing to the slice to some other slice. To set the slice, do this instead:
*endpointsList=list

Related

Golang - printing the content of the variable

I am new to Golang and I am wondering how can I print the actual values of a struct that doc.Find() returns. I am using this package that has this methods.
So, for example if I do this:
casesCounter := doc.Find(".cases-counter li")
fmt.Printf("%T\n", casesCounter)
fmt.Println(&casesCounter)
fmt.Println(casesCounter)
I have also tried with using the pointer:
casesCounter := *doc.Find(".cases-counter li")
For each case I got memory addresses printed:
&{[0xc0004108c0 0xc000410b60] 0xc00023f720 0xc000230150}
{[0xc0004108c0 0xc000410b60] 0xc00023f720 0xc000230150}
But, how can I get the actual values of this struct, same as I when I would do console.log() in javascript?
From the documentation, calling
doc.Find(selector string)
returns a pointer to the selection
You should therefore access the data through the selection, whose structure is documented here
I suppose you want to access the nodes, and as Latif mentioned, this can be done via a loop, as this is an array as documented above
for _, v := range casesCounter.Nodes {
fmt.Printf("%+v", v)
}
You should try the following code:
for _, v := range casesCounter.Nodes {
fmt.Printf("%+v", v)
}

How to Make array of elements with type specified at run time

I am trying to create a array of elements with a type known only at the run time (a pkg API gets to retrieve elements in json and convert to struct). I have a helper function something like below, which takes an interface as a param and trying to get the type of interface while calling make.
golang compiler doesn't seems to like it.
var whatAmI = func(i interface{}) {
a := reflect.TypeOf(i)
//var typ reflect.Type = a
b := make (a, 10) //10 elem with type of i
//b := new (typ)
fmt.Printf ("a: %v b: %v", a, b)
}
prog.go:21:14: a is not a type
I tried various combinations of reflects but no help so far.
This seems to me can be a common problem to run in to. How can I solve/workaround this?
Get the type for a slice given a value of the element type, v:
sliceType := reflect.SliceOf(reflect.TypeOf(v))
Create a slice with length and capacity (both 10 here).
slice:= reflect.MakeSlice(sliceType, 10, 10)
Depending on what you are doing, you may want to get the actual slice value by calling Interface() on the reflect.Value:
s := slice.Interface()
Run it on the playground.
Just make like :
b := make([]interface{}, 10)
for i := range b {
b[i] = reflect.Zero(a)
}

Pass slice as function argument, and modify the original slice

I know everything is passed by value in Go, meaning if I give a slice to a function and that function appends to the slice using the builtin append function, then the original slice will not have the values that were appended in the scope of the function.
For instance:
nums := []int{1, 2, 3}
func addToNumbs(nums []int) []int {
nums = append(nums, 4)
fmt.Println(nums) // []int{1, 2, 3, 4}
}
fmt.Println(nums) // []int{1, 2, 3}
This causes a problem for me, because I am trying to do recursion on an accumulated slice, basically a reduce type function except the reducer calls itself.
Here is an example:
func Validate(obj Validatable) ([]ValidationMessage, error) {
messages := make([]ValidationMessage, 0)
if err := validate(obj, messages); err != nil {
return messages, err
}
return messages, nil
}
func validate(obj Validatable, accumulator []ValidationMessage) error {
// If something is true, recurse
if something {
if err := validate(obj, accumulator); err != nil {
return err
}
}
// Append to the accumulator passed in
accumulator = append(accumulator, message)
return nil
}
The code above gives me the same error as the first example, in that the accumulator does not get all the appended values because they only exist within the scope of the function.
To solve this, I pass in a pointer struct into the function, and that struct contains the accumulator. That solution works nicely.
My question is, is there a better way to do this, and is my approach idiomatic to Go?
Updated solution (thanks to icza):
I just return the slice in the recursed function. Such a facepalm, should have thought of that.
func Validate(obj Validatable) ([]ValidationMessage, error) {
messages := make([]ValidationMessage, 0)
return validate(obj, messages)
}
func validate(obj Validatable, messages []ValidationMessage) ([]ValidationMessage, error) {
err := v.Struct(obj)
if _, ok := err.(*validator.InvalidValidationError); ok {
return []ValidationMessage{}, errors.New(err.Error())
}
if _, ok := err.(validator.ValidationErrors); ok {
messageMap := obj.Validate()
for _, err := range err.(validator.ValidationErrors) {
f := err.StructField()
t := err.Tag()
if v, ok := err.Value().(Validatable); ok {
return validate(v, messages)
} else if _, ok := messageMap[f]; ok {
if _, ok := messageMap[f][t]; ok {
messages = append(messages, ValidationMessage(messageMap[f][t]))
}
}
}
}
return messages, nil
}
If you want to pass a slice as a parameter to a function, and have that function modify the original slice, then you have to pass a pointer to the slice:
func myAppend(list *[]string, value string) {
*list = append(*list, value)
}
I have no idea if the Go compiler is naive or smart about this; performance is left as an exercise for the comment section.
For junior coders out there, please note that this code is provided without error checking. For example, this code will panic if list is nil.
Slice grows dynamically as required if the current size of the slice is not sufficient to append new value thereby changing the underlying array. If this new slice is not returned, your append change will not be visible.
Example:
package main
import (
"fmt"
)
func noReturn(a []int, data ...int) {
a = append(a, data...)
}
func returnS(a []int, data ...int) []int {
return append(a, data...)
}
func main() {
a := make([]int, 1)
noReturn(a, 1, 2, 3)
fmt.Println(a) // append changes will not visible since slice size grew on demand changing underlying array
a = returnS(a, 1, 2, 3)
fmt.Println(a) // append changes will be visible here since your are returning the new updated slice
}
Result:
[0]
[0 1 2 3]
Note:
You don't have to return the slice if you are updating items in the slice without adding new items to slice
Slice you passed is an reference to an array, which means the size is fixed. If you just modified the stored values, that's ok, the value will be updated outside the called function.
But if you added new element to the slice, it will reslice to accommodate new element, in other words, a new slice will be created and old slice will not be overwritten.
As a summary, if you need to extend or cut the slice, pass the pointer to the slice.Otherwise, use slice itself is good enough.
Update
I need to explain some important facts. For adding new elements to a slice which was passed as a value to a function, there are 2 cases:
A
the underlying array reached its capacity, a new slice created to replace the origin one, obviously the origin slice will not be modified.
B
the underlying array has not reached its capacity, and was modified. BUT the field len of the slice was not overwritten because the slice was passed by value. As a result, the origin slice will not aware its len was modified, which result in the slice not modified.
When appending data into slice, if the underlying array of the slice doesn't have enough space, a new array will be allocated. Then the elements in old array will be copied into this new memory, accompanied with adding new data behind

Go: append directly to slice found in a map

I wanted to create a map of slices where values are appended to the corresponding slice. However, when trying to append directly to the slice returned by accessing it (see comment below), it would not be stored, so I had to go with the long form access (line below the comment).
Why is it so? I expected the access to the map to return some sort of pointer, so in my mind mappedAminoAcid == aminoAcidsToCodons[aminoAcid]; clearly, I'm wrong.
Thanks!
aminoAcidsToCodons := map[rune][]string{}
for codon, aminoAcid := range utils.CodonsToAminoAcid {
mappedAminoAcid, ok := aminoAcidsToCodons[aminoAcid]
if ok {
// NOT WORKING: mappedAminoAcid = append(mappedAminoAcid, codon)
aminoAcidsToCodons[aminoAcid] = append(mappedAminoAcid, codon)
} else {
aminoAcidsToCodons[aminoAcid] = []string{codon}
}
}
append returns a new slice if the underlying array has to grow to accomodate the new element. So yes, you have to put the new slice back into the map. This is no different from how strings work, for instance:
var x map[string]string
x["a"] = "foo"
y := x["a"]
y = "bar"
// x["a"] is still "foo"
Since a nil slice is a perfectly fine first argument for append, you can simplify your code to:
aminoAcidsToCodons := map[rune][]string{}
for codon, aminoAcid := range utils.CodonsToAminoAcid {
aminoAcidsToCodons[aminoAcid] = append(aminoAcidsToCodons[aminoAcid], codon)
}

Create a slice of type from a pointer to a type

Trying to create a slice in which the type is set dynamicaly based on a pointer to a specific type, so i made the following sample
func main() {
var chicken *Chicken
//create a slice of chickens
chickens:=GetaDynamiclyTypedSlice(chicken)
//this throws cannot range over chickens (type *[]interface {}) and i cant figure how to create a slice using my above chicken pointer
for _,chicken := range chickens{
fmt.Println(chicken)
}
}
type Chicken struct{
Weight float64
}
func GetaDynamiclyTypedSlice(ptrItemType interface{})*[]interface {}{
var collection []interface{}
itemtyp := reflect.TypeOf(ptrItemType).Elem()
for i:=0;i<1000;i++{
//create an item of the wanted type
item := reflect.New(itemtyp)
//set a random float to the weight value
item.Elem().FieldByName("Weight").SetFloat(rnd.ExpFloat64())
collection = append(collection,&item)
}
return &collection
}
what should i do to be able to use range on the returned slice?
how can i use the itemtyp as the type of my slice?
There are few problems with your code.
You're returning a pointer to a reflect.Value, 99% sure that's not what you're trying to achive.
You're not dereferencing the slice like Simon mentioned.
Slices are pointer types, if you're returning *[]interface{} for performance reasons, you're actually hurting not helping.
So let's rewrite the code and optimize it! (it's late night SO, time to party):
// pass the size to preallocate the slice, also return the correct slice type.
func GetaDynamiclyTypedSlice(ptrItemType interface{}, size int) (col []interface{}) {
col = make([]interface{}, size)
itemtyp := reflect.TypeOf(ptrItemType).Elem()
for i := range col { //prettier than for i := 0; etc etc
item := reflect.New(itemtyp)
item.Elem().FieldByName("Weight").SetFloat(rand.ExpFloat64())
col[i] = item.Interface() //this is the magic word, return the actual item, not reflect.Value
}
return
}
playground
You just need to dereference the pointer (so you're not iterating over a pointer - you're iterating over a slice):
for _, chicken := range *chickens {
// ...
}
Playground link: http://play.golang.org/p/NBv9sooqEV

Resources