Golang - printing the content of the variable - go

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)
}

Related

Golang iterate over map of interfaces

I am trying to iterate over a map of interfaces in golang, it has the below structure, I am able to use for loop to iterate to a single level but couldn't go deep to get values of the interface.
Yaml
steps:
execute:
- mvn : 1.9.3
goals: 'clean install'
concurrent: false
- mvn : 1.9.3
goals: 'dependency-check:check'
concurrent: false
Go
// reading a yaml file
// trying to use "gopkg.in/yaml.v2" package
data, err := ioutil.ReadFile(fileName)
m := make(map[interface{}]interface{})
err = yaml.Unmarshal([]byte(data), &m)
for k, v := range m {
// Trying to explore the data here
fmt.Println("k:", k, "v:", v)
}
Output of
fmt.Printf("--- m:\n%v\n\n", m)
looks like below
map[steps:map[execute:[map[concurrent:false goals:clean install mvn:1.9.3] map[concurrent:false goals:dependency-check:check mvn:1.9.3]]]]
My attempt
for k, v := range m {
fmt.Println("k:", k, "v:", v)
}
Assuming that you have a tree of map[interface{}]interface{} and []interface{}, use the following code to walk the tree:
func walk(v interface{}) {
switch v := v.(type) {
case []interface{}:
for i, v := range v {
fmt.Println("index:", i)
walk(v)
}
case map[interface{}]interface{}:
for k, v := range v {
fmt.Println("key:", k)
walk(v)
}
default:
fmt.Println(v)
}
}
This code recurses down the structure and uses type switches to find the slices and maps.
Use it like this:
data, err := ioutil.ReadFile(fileName)
var m map[interface{}]interface{}
err = yaml.Unmarshal([]byte(data), &m)
walk(m)
Run it on the playground
To access the Execute object and iterate over it you have to do a lot of type assertions like the answer given by #vooker.
Actually it's not recommended to use map[interface{}]interface{} for unmarshaling process. It should be unmarshalled to a concrete type as a struct.
From the YAML structure, it could be translated as a struct type like this:
type data struct {
Steps struct {
Execute []execute `yaml:"execute"`
} `yaml:"steps"`
}
type execute struct {
MVN string `yaml:"mvn"`
Goals string `yaml:"goals"`
Concurrent bool `yaml:"concurrent"`
}
And from the structure, it is easier to access the unmarshalled data from the YAML. For example, if you want to iterate over the "execute" object you could do something like this:
var result data
yaml.Unmarshal([]byte(str), &result)
fmt.Println(result)
// iterate over the slice of object
for _, e := range result.Steps.Execute {
fmt.Println()
fmt.Println("mvn:", e.MVN)
fmt.Println("goals:", e.Goals)
fmt.Println("concurrent:", e.Concurrent)
}
Try it on the playground
I don't know what you mean with that "value of m" as that doesn't look like any format I've seen in Go so I'll talk to a few situations: When the interfaces are probably types you know what they are vs when the interfaces could be anything and you aren't sure.
If there are only a couple of types that you know went into the map, you can do a type switch and handle each type individually. This would give you the opportunity to reference subfields and print them as well. If you always print the same info for the same type of objects, you could look into adding a String() string function to your structs which will make them implement the Stringer interface and then you can print the object and your String() func will get called even if it's boxed as an interface.
If you're working with a library that's filling the map, or there's simply too big a diversity of the types in the map for a type switch to be reasonable, then you'll either want a generic solution such as a library like spew or a custom solution written with reflection.

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)
}

How do I pass multiple non-empty values of a struct to hmset in golang?

With reference to this:
https://play.golang.org/p/0kYRHO5f7kE
If I have 20+ different fields, if one of the fields in the Struct is empty, don't update it. Only update the ones with values in them.
What's the best way forward? I've seen passing as variadic input to another function but how best can I do this elegantly?
you can use this library to convert your struct fields into map of interfaces (can be done by yourself using reflect from stdlib) then loop over it
pipe := redisClient.TxPipeline()
m := structs.Map(server)
for k, v := range m {
pipe.HMSet(username, k, v)
}
cmder, err := pipe.Exec()
if err != nil {
return nil, err
}
the driver for redis used is go-redis

How to understand this behavior of goroutine?

package main
import (
"fmt"
"time"
)
type field struct {
name string
}
func (p *field) print() {
fmt.Println(p.name)
}
func main() {
data := []field{ {"one"},{"two"},{"three"} }
for _,v := range data {
go v.print()
}
<-time.After(1 * time.Second)
}
why does this code print 3 "three" instead of "one" "two" "three" in any order?
There is a data race.
The code implicitly takes address of variable v when evaluating arguments to the goroutine function. Note that the call v.print() is shorthand for the call (&v).print().
The loop changes the value of variable v.
When goroutines execute, it so happens that v has the last value of the loop. That's not guaranteed. It could execute as you expected.
It's helpful and easy to run programs with the race detector. This data race is detected and reported by the detector.
One fix is to create another variable scoped to the inside of the loop:
for _, v := range data {
v := v // short variable declaration of new variable `v`.
go v.print()
}
With this change, the address of the inner variable v is taken when evaluating the arguments to the goroutine. There is a unique inner variable v for each iteration of the loop.
Yet another way to fix the problem is use a slice of pointers:
data := []*field{ {"one"},{"two"},{"three"} } // note '*'
for _, v := range data {
go v.print()
}
With this change, the individual pointers in the slice are passed to the goroutine, not the address of the range variable v.
Another fix is to use the address of the slice element:
data := []field{ {"one"},{"two"},{"three"} } // note '*'
for i:= range data {
v := &data[i]
go v.print()
}
Because pointer values are typically used with types having a pointer receiver, this subtle issue does not come up often in practice. Because field has a pointer receiver, it would be typical to use []*field instead of []field for the type of data in the question.
If the goroutine function is in an anonymous function, then a common approach for avoiding the issue is to pass the range variables as an argument to the anonymous function:
for _, v := range data {
go func(v field) {
v.print() // take address of argument v, not range variable v.
}(v)
}
Because the code in the question does not already use an anonymous function for the goroutine, the first approach used in this answer is simpler.
As stated above there’s a race condition it’s result depends on delays on different processes and not well defined and predictable.
For example if you add time.Sleep(1*time.Seconds) you likely to get a correct result. Because usually goroutine prints faster than 1second and will have correct variable v but it’s a very bad way.
Golang has a special race detector tool which helps to find such situations. I recommend read about it while reading testing. Definitely it’s worth it.
There’s another way - explicitly pass variable value at goroutine start:
for _, v := range data {
go func(iv field) {
iv.print()
}(v)
}
Here v will be copied to iv (“internal v”) on every iteration and each goroutine will use correct value.

Pointer to loop variable for range over map or slice of interface{}

I'm using go-hdf5 and I'm hitting a problem when trying to write attributes in a loop from a map.
The attributes are created correctly (correct name and datatype) but the written value is garbage.
The same code outside of the loop works fine. I tried both the v := v idiom and wrapping the code in a closure to capture v but it doesn't make a difference.
Here is the gist of the code (error checking intentionally left out for clarity):
m := map[string]interface{"foo", 42}
for k, v := range m {
// [...]
v := v
attr.Write(&v, dtype)
}
The Write method is using reflection to grab a pointer to the value and forwards it to the C library. The relevant part of the code is just:
func (s *Attribute) Write(data interface{}, dtype *Datatype) error {
v := reflect.ValueOf(data)
addr := unsafe.Pointer(v.Pointer())
return h5err(C.H5Awrite(s.id, dtype.id, addr))
}
If I replace the map by a slice of interface{}, I get the exact same problem so my hunch is that this has to do with the binding of loop variables, but yet v := v doesn't help so I'm not sure.
I'm quite familiar with Go, HDF5 (C library) and go-hdf5 but I'm really stuck here. Any idea?
BTW I'm using go1.5.1 darwin/amd64.
The Write method needs a pointer to a value, not a pointer to an interface containing the value. You can get it using reflection:
u := reflect.New(reflect.ValueOf(v).Type())
u.Elem().Set(reflect.ValueOf(v))
v := u.Interface()

Resources