Can I obtain a pointer to a map value in golang? - go

I'm trying to use Go's flag package to dynamically generate FlagSets and collect the results in a map from flagname -> flag value.
My code looks like this:
import "flag"
fs := flag.NewFlagSet(strings.Join(commands, " "), flag.ExitOnError)
requiredFlags := []string{"flagA", "flagB"}
flags := make(map[string]string)
for _, f := range requiredFlags {
flags[f] = *fs.String(f, "", "")
}
This code compiles, but the map never gets updated after the FlagSet fs is parsed, so the values of "flagA" and "flagB" are both "". So this makes sense to me; flags is of type map[string]string after all, not map[string]*string. Unfortunately, I can't seem to fix this problem using pointers. I've tried every combination of referencing and dereferencing I can think of and I either end up with a nil pointer dereference (runtime error) or invalid indirect (compile time error).
How can I set up the map and FlagSet such that the map values are populated after the FlagSet is parsed?

What is wrong with
flags := make(map[string]*string)
for _, f := range requiredFlags {
flags[f] = fs.String(f, "", "")
}
...
println(*(flags["flagA"]))
?

Related

Golang manipulating object inside a sync.Map

I am trying to manipulate a golang sync.Map of sync.Map, but I have some issues with the casting.
I have the following code:
func (cluster *Cluster) action(object1, object2 MyObject) {
value, _ := cluster.globalMap.LoadOrStore(object1.name, sync.Map{})
localMap := value.(sync.Map)
localMap.Store(object2.Name, object2)
value2, _ := cluster.resourceInflight.Load(node.Name)
forComparison := value2.(sync.Map)
fmt.Println(localMap.Load(object2.Name))
fmt.Println(forComparison.Load(object2.Name))
}
{myObject map[] map[]} true
<nil> false
I am doing this since I wish to keep the content of localMap thread safe.
The problem is I am expecting to have the same result for my two print, as "forComparison" should be pointing to the same object than "localMap". But second result is nil.
I am suspecting that the problem is coming from the casting of the interface "value" into an actual "sync.Map". But I am not sure how I can actually call the .Store method with inline casting.
I thought about Storing localMap inside cluster.globalMap, but this seems incorrect to me as it would break the whole point of using a localSyncMap and create concurrency issues.
Any input on what I should do ?
As per the comments the issue was that you were copying a sync.Map; the following code will fail (output "Not found" - playground):
var sm sync.Map
var x interface{}
x = sm
sm2 := x.(sync.Map)
sm2.Store("test", "test")
result, ok := sm.Load("test")
if ok {
fmt.Printf("Found: %s\n", result)
} else {
fmt.Printf("Not found\n")
}
Whereas using a pointer works as expected:
var sm sync.Map
var x interface{}
x = &sm
sm2 := x.(*sync.Map)
sm2.Store("test", "test")
result, ok := sm.Load("test")
if ok {
fmt.Printf("Found: %s\n", result)
} else {
fmt.Printf("Not found\n")
}
Running go vet would probably have warned you about other issues (sync.Map contains a sync.Mutex and these "must not be copied after first use").
Note that the docs for Sync.Map state:
The Map type is specialized. Most code should use a plain Go map instead, with separate locking or coordination, for better type safety and to make it easier to maintain other invariants along with the map content.

instantiate by reflection

Given a function with a parameter (that is a pointer to a struct) I want to instantiate a type of this parameter.
For example, for this function:
func MyFunction(myStruct *MyStruct) {}
using reflection I want to create a variable that contains exactly same as x := &MyStruct{} would contain.
This is the code example:
package main
import (
"fmt"
"reflect"
)
type MyStruct struct {
}
func main () {
reflectedFunction := reflect.TypeOf(MyFunction)
argType := reflectedFunction.In(0)
reflectedParameter := reflect.New(argType)
actual := reflectedParameter.Interface()
fmt.Println(actual)
expected := &MyStruct{}
fmt.Println(expected)
}
func MyFunction(myStruct *MyStruct) {
}
If you execute it, you'll see that they contain different info:
0xc00000e028 // actual
&{} // expected
This question isn't about why I would like to do this, so please avoid recommending not doing it, etc.
In your code, actual is a interface{} value containing a *MyStruct. As the name and documentation indicate, reflectedParameter.Interface() returns an interface{}.
using reflection I want to create a variable that contains exactly same as x := &MyStruct{} would contain.
Then you'll have to type assert it:
actual := reflectedParameter.Elem().Interface().(*MyStruct)
reflect.New creates a pointer to a new zero value of the reflected type. In your example that type is already a *MyStruct, so the value of your actual winds up being a representation of a **MyStruct, as seen in https://play.golang.org/p/Nyuc0mYmgkZ. Taking the .Elem() of that results in the correct type again, but you end up with a nil pointer (*MyStruct)(nil).
You need to take the .Elem() if that first type if you want to create a new pointer value.
reflectedParameter := reflect.New(argType.Elem())
https://play.golang.org/p/QzwTFUH3HTs
reflectedFunction := reflect.TypeOf(MyFunction)
argType := reflectedFunction.In(0)
reflectedParameter := reflect.New(argType.Elem())
actual := reflectedParameter.Interface()
fmt.Printf("%#v\n", actual)
expected := &MyStruct{}
fmt.Printf("%#v\n", expected)
Which prints
&main.MyStruct{}
&main.MyStruct{}

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 can I log the value of passed parameters to a function?

My aim is to create a logging function that lists the name of a function and the list of passed parameters.
An example would be the following:
func MyFunc(a string, b int){
... some code ...
if err != nil{
errorDescription := myLoggingFunction(err)
fmt.Println(errorDescription)
}
}
func main(){
MyFunc("hello", 42)
}
// where MyLoggingFunction should return something like:
// "MyFunc: a = hello, b = 42, receivedError = "dummy error description"
So far it seems that in Go there is no way to get the name of the parameters of a function at runtime, as answered in this question, but I could give up this feature.
I've managed to get the function name and the memory address of the passed parameters by analysing the stack trace, but I'm hitting a wall when it comes to print somehow the parameters starting from their address (I understand that it might not be trivial depending on the type of the parameters, but even something very simple will do for now)
This is an implementation of the logging function I'm building (you can test it on this playground), is there away to print the parameter values?
func MyLoggingFunction(err error) string {
callersPCs := make([]uintptr, 10)
n := runtime.Callers(2, callersPCs) //skip first 2 entries, (Callers, GetStackTrace)
callersPCs = callersPCs[:n]
b := make([]byte, 1000)
runtime.Stack(b, false)
stackString := string(b)
frames := runtime.CallersFrames(callersPCs)
frame, _ := frames.Next()
trimmedString := strings.Split(strings.Split(stackString, "(")[2], ")")[0]
trimmedString = strings.Replace(trimmedString, " ", "", -1)
parametersPointers := strings.Split(trimmedString, ",")
return fmt.Sprintf("Name: %s \nParameters: %s \nReceived Error: %s", frame.Function, parametersPointers, err.Error())
}
If there are other ideas for building such logging function without analysing the stack trace, except the one that consists in passing a map[string]interface{} containing all the passed parameter names as keys and their values as values (that is my current implementation and is tedious since I'd like to log errors very often), I'd be glad to read them.

golang de-reference a map

Here is a sample code that creates a Map of string keys having value of bool.
myMap := make(map[string]bool)
myMap["Jan"] = true
myMap["Feb"] = false
myMap["Mar"] = true
After doing some operation on this map, I want to delete it. I don't want to use for loop to iterate through each key and delete.
If I do re-initialize myMap again (like following), does it de-references the original and subject to garbage collection?
myMap = make(map[string]bool)
Golang FAQ on garbage collection:
Each variable in Go exists as long as there are references to it. If
the compiler cannot prove that the variable is not referenced after
the function returns, then the compiler must allocate the variable on
the garbage-collected heap to avoid dangling pointer errors.
In case there are no references used for the current map it will be garbage collected by the language. But for deleting a map There is no process other than looping over it and delete the keys one by one. as
myMap := make(map[string]bool)
for k, _ := range myMap{
delete(myMap, k)
}
If you re-initialze the map using make it will not going to de-reference the same it will clear the map but will not dereference it. If you check for its len it will become zero
package main
import (
"fmt"
)
func main() {
myMap := make(map[string]bool)
myMap["Jan"] = true
myMap["Feb"] = false
myMap["Mar"] = true
fmt.Println(len(myMap))
myMap = make(map[string]bool)
fmt.Println(len(myMap))
}
Along with that if you prints the address it points to same address.
fmt.Printf("address: %p \n", &myMap)
myMap = make(map[string]bool)
fmt.Printf("address: %p ", &myMap)
Playground Example

Resources