Reflection struct field.Set with a Flag pointer value - pointers

I have a bunch of flags parsed, and I'm then trying to assign those values to fields in a struct, but I'm struggling to get a parsed flag value set into the struct because I can't type assert it or cast it.
Here is a snippet of the code I have. It's not important to worry too much about the IterFields function, basically the third argument is called for each field in the struct...
Note: there are comments in the code below which highlight the error(s).
flag.Parse()
IterFields(st, v, func(field reflect.Value, sf reflect.StructField) {
flag.VisitAll(func(f *flag.Flag) {
if f.Name == strings.ToLower(sf.Name) || f.Name == sf.Tag.Get("short") {
fmt.Printf("%+v, %T\n", f.Value, f.Value)
// PRINTS: true, *flag.boolValue
if v, ok := f.Value.(bool); ok {
fmt.Println("ok")
} else {
fmt.Println("not ok")
}
// ERROR: impossible type assertion: bool does not implement flag.Value (missing Set method)
field.Set(reflect.ValueOf(f.Value))
// PANIC: value of type *flag.boolValue is not assignable to type bool
}
})
})

f.Value is an interface type flag.Value abstracting all kinds of flag values. As your code indicates, it's not of type bool but some non-exported *flag.boolValue. You shouldn't be concerned about its dynamic type.
You may use the Value.String() method to get its value as a string, which will be either "false" or "true" for bool types, you may use simple comparison to obtain a bool from it like f.Value.String() == "true".
But a better approach would be: all flag.Value values originating from the flag package also implement flag.Getter which also has a Get() method that will directly return a bool value in case of a bool flag (wrapped in interface{} of course). Just use that:
field.Set(reflect.ValueOf(f.Value.(flag.Getter).Get()))
The above works for fields of any type (given that the flag's value type is assignable to the field's type).
For bool fields only, alternatively you may also use:
field.SetBool(f.Value.(flag.Getter).Get().(bool))

Related

Why does Go's package flag use pointers?

Consider the following code from gopl.io/ch2/echo4
package main
import (
"flag"
"fmt"
"strings"
)
var n = flag.Bool("n", false, "omit trailing newline")
var sep = flag.String("s", " ", "separator")
func main() {
flag.Parse()
fmt.Print(strings.Join(flag.Args(), *sep))
if !*n {
fmt.Println()
}
}
I'm interested why the variables n and sep are pointers to the flag variables, rather than normal variable type.
It is because they need to be assigned value after they are created. The order of actions is:
Create variable var n = flag.Bool("n", false, "omit trailing newline") The value is false now.
Assign value with flag.Parse(). Variable is now assigned value passed as command line argument.
If you check the code here, you'll see that there's an exported variable called CommandLine, which is a pointer to a FlagSet. This is where the magic happens. When you import that library, it's instantiated. When you invoke the exported functions, for example, flag.Bool(), that function, in turn, calls the method Bool(), which has a pointer receiver to...FlagSet. It will create a new bool to store your flag's value, invoke BoolVar() to store a pointer to the newly created bool variable within the FlagSet data structure (you'll need to trace BoolVar to see how this is accomplished), and returns the very same pointer to you so you can later get the current value (which could be the default value or an entirely new value as a result of the call toParse())
// CommandLine is the default set of command-line flags, parsed from os.Args.
// The top-level functions such as BoolVar, Arg, and so on are wrappers for the
// methods of CommandLine.
var CommandLine = NewFlagSet(os.Args[0], ExitOnError)
// NewFlagSet returns a new, empty flag set with the specified name and
// error handling property. If the name is not empty, it will be printed
// in the default usage message and in error messages.
func NewFlagSet(name string, errorHandling ErrorHandling) *FlagSet {
f := &FlagSet{
name: name,
errorHandling: errorHandling,
}
f.Usage = f.defaultUsage
return f
}
// A FlagSet represents a set of defined flags. The zero value of a FlagSet
// has no name and has ContinueOnError error handling.
//
// Flag names must be unique within a FlagSet. An attempt to define a flag whose
// name is already in use will cause a panic.
type FlagSet struct {
// Usage is the function called when an error occurs while parsing flags.
// The field is a function (not a method) that may be changed to point to
// a custom error handler. What happens after Usage is called depends
// on the ErrorHandling setting; for the command line, this defaults
// to ExitOnError, which exits the program after calling Usage.
Usage func()
name string
parsed bool
actual map[string]*Flag
formal map[string]*Flag
args []string // arguments after flags
errorHandling ErrorHandling
output io.Writer // nil means stderr; use Output() accessor
}
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func (f *FlagSet) Bool(name string, value bool, usage string) *bool {
p := new(bool)
f.BoolVar(p, name, value, usage)
return p
}
// Bool defines a bool flag with specified name, default value, and usage string.
// The return value is the address of a bool variable that stores the value of the flag.
func Bool(name string, value bool, usage string) *bool {
return CommandLine.Bool(name, value, usage)
}
Going back to your question:
why the variables n and sep are pointers to the flag variables, rather than normal variable type.
It's because Parse() can manipulate the original variables and your new variables n and sep would have only captured a copy of the original values. By using the pointer, you and the FlagSet are looking at exact the same variables.

Cannot take the address of map element

I want to find out why
x:= odsMap[segRef]
x.GetValue("#OriginDestinationKey")
works, but this does not:
odsMap[segRef].GetValue("#OriginDestinationKey")
?
The last snippet prints the following errors:
cannot call pointer method on odsMap[segRef]go
cannot take the address of odsMap[segRef]
These errors happen during compilation time (not runtime). So, my main question is why I need an intermediate variable x to access the function?
Regarding the type of the variables odsMap is a map[string] XMLElement and segRef is a string.
Thanks.
Map index expressions are not addressable, because the internals of a map may change when a new entry is added to it, so the spec intentionally does not allow taking its address (this gives greater freedom for map implementations).
This means if you store non-pointers in the map, and you want to call a method of a stored value that has a pointer receiver, that would require to take the address of the non-pointer value (to be used as the receiver), but since map index expressions are not addressable, that results in a compile-time error.
A workaround is to store pointer values in the map, so there is no need to take the address of an index expression, because it's already a pointer. An example of this can be seen in this answer: Why should constructor of Go return address? If we have this type:
type My int
func (m *My) Str() string { return strconv.Itoa(int(*m)) }
This gives the compile-time error in question:
m := map[int]My{0: My(12)}
m[0].Str() // Error!
But this works:
m := map[int]*My{}
my := My(12)
m[0] = &my // Store a pointer in the map
m[0].Str() // You can call it, no need to take the address of m[0]
// as it is already a pointer
Another option is to assign it to a local variable whose address can be taken, and call the pointer method on that. Care must be taken though, as if the method has pointer receiver, it might modify pointed object or its components (e.g. fields of a struct), which would not be reflected in the value stored in the map. If you go down this path, you might have to reassign the value to the key in the map to have the updated value.
All-in-all, if you have a value whose type has methods with pointer receiver, you're better off using it (store, pass) as a pointer and not as a non-pointer value.
See related questions:
Pointer methods on non pointer types
How can I store reference to the result of an operation in Go?
#icza's answer is the correct one.
Here is an example to illustrate how "value receiver" vs "pointer receiver" interact with "pointer map" vs "values map" :
https://play.golang.org/p/JVp6DirgPkU
package main
import (
"fmt"
)
// a simple type, with two methods : one with a value receiver, one with a pointer receiver
type Item struct {
name string
}
func (i Item) GetNameByValue() string {
return i.name
}
func (i *Item) GetNameByRef() string {
return i.name
}
func main() {
{
// in this map, we store *pointers* to Item values
mapByRef := make(map[int]*Item)
mapByRef[0] = &Item{"I am stored as a pointer"}
// GetNameByRef will work on a *Item : "mapByRef[0]" is already a pointer
fmt.Println("GetByRef :", mapByRef[0].GetNameByRef())
// GetNameByValue will work on a *Item : go automatically turns this into '(*mapByRef[0]).GetNameByValue()', and this is valid
fmt.Println("GetByValue :", mapByRef[0].GetNameByValue())
}
{
// in this map, we store Item values (no pointers)
mapByValue := make(map[int]Item)
mapByValue[0] = Item{"I am stored as a value"}
// GetNameByValue will work on a Item : "mapByValue[0]" has the right type
fmt.Println("GetByValue :", mapByValue[0].GetNameByValue())
// GetNameByRef will not work : go tries to turn this into : (&mapByValue[0]).GetNameByRef(),
// and go refuses to let you take the address of a value inside a map
// fmt.Println("GetByRef :", mapByValue[0].GetNameByRef())
// compiler error :
// ./prog.go:47:46: cannot call pointer method on mapByValue[0]
// ./prog.go:47:46: cannot take the address of mapByValue[0]
// you will need some way to copy the value before taking its address :
item := mapByValue[0]
fmt.Println("item.GetByRef :", item.GetNameByRef())
// same as :
fmt.Println("(&item).GetByRef :", (&item).GetNameByRef())
}
}
// Output :
//
// GetByRef : I am stored as a pointer
// GetByValue : I am stored as a pointer
// GetByValue : I am stored as a value
// item.GetByRef : I am stored as a value
// (&item).GetByRef : I am stored as a value

If the type of a parameter is interface{} how do you know whether you pass by pointer or by value?

Given any function that takes a parameter of type interface{} how would I know whether or not to pass that parameter with or without & without navigating the source code of the function.
For example if I had a function with this type signature given to me:
func foo(x interface{}, y int) int
Would there be any way to figure out if x was supposed to be passed by value or by pointer?
Here is the snippet from the source:
// DecodeElement works like Unmarshal except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to Unmarshal for some elements.
func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal")
}
return d.unmarshal(val.Elem(), start)
}
It is checking val.Kind() != reflect.Ptr Which means you have to pass the pointer i.e &v.
Its entirely depend on the person who wrote the method or function, so interface{} could be either *ptr or anything but u ve to check that inside your function using reflect.ValueOf(v).Kind() whether the value is a pointer or not and proceeds accordingly.
And little bit about empty interface:
The interface type that specifies zero methods is known as the empty interface:
interface{}
An empty interface may hold values of any type. (Every type implements at least zero methods.)
Empty interfaces are used by code that handles values of unknown type. For example, fmt.Print takes any number of arguments of type interface{}.
Another useful discussion: docs
DecodeElement() and friends have a formal v interface{} whose type is documented in the Unmarshal() function documentation:
Unmarshal parses the XML-encoded data and stores the result in the
value pointed to by v, which must be an arbitrary struct, slice, or
string.
So to literally answer your question, no, you cannot know without reading the source - if the value you want to pass is a struct proper, you need to indirect. If it is already a pointer to that struct, you do not.
For example:
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
var (
a Result
b *Result
c string
)
xmlDecoder.DecodeElement(&a, startElement)
xmlDecoder.DecodeElement(&c, startElement)
but
xmlDecoder.DecodeElement(b, startElement)

How to force passing parameter as a pointer in Go?

I am implementing an application layer network protocol which uses JSON in Go.
func ReadMessage(conn net.Conn, returnMessage interface{}) bool {
messageBytes := // read from conn
error := json.Unmarshal(messageBytes, &returnMessage)
if error != nil {
return false
}
return true
}
The function takes a struct as its second parameter where the message is unmarshalled. The function can be called like this:
msg := MessageType1{}
ok := ReadMessage(conn, &msg)
Or without the ampersand (&)
msg := MessageType1{}
ok := ReadMessage(conn, msg)
which will compile, but not do what is should as the struct is passed as a copy, not as a reference and the original msg will remain empty. So I'd like to force passing the struct by reference and catch this error at compile time.
Changing the parameter type to *interface{} will not compile:
cannot use &msg (type *MessageType1) as type *interface {} in function argument:
*interface {} is pointer to interface, not interface
Is there some Go style way of doing this correctly?
There is not a way to do this in the function declaration.
You can use reflection though and panic at runtime when the argument is not a pointer.
However maybe you should consider changing the design of your code. The concrete type of the argument should not matter. It either implements the interface you need or not.
Demo: http://play.golang.org/p/7Dw0EkFzbx
Since Go 1.18 you can do this using generics:
func test[T any](dst *T) {
//Do something with dst
}
You can't enforce this as *T always has the method set of T. Thus both implement the interface.
From the spec:
The method set of any other type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).
What you can do instead is to use the language's ability to return multiple values in your function, as Volker already stated:
func ReadMessage(conn net.Conn) (interface{}, bool) {
var returnMessage interface{}
messageBytes := // read from conn
error := json.Unmarshal(messageBytes, &returnMessage)
if error != nil {
return nil, false
}
return returnMessage, true
}
You should also consider not returning type interface{} but some meaningful type.

In go reflection package, is the call Value.Kind() a syntactic sugar to Value.Type().Kind()?

Both of the reflect.Type interface and reflect.Value type implement the same Kind() method signature, suppose that we have some value object v := reflect.ValueOf(x)
Is v.Kind() just call v.Type().Kind() ?
They contain the same value, but do not seem to refer to the same thing:
type.go source
value.go source
A Type is usually implemented by unexported struct rtype (via TypeOf), while the Value contains a *rtype and extends flag, which is itself a reduced form of the Kind:
// flag holds metadata about the value.
// The lowest bits are flag bits:
// - flagRO: obtained via unexported field, so read-only
// - flagIndir: val holds a pointer to the data
// - flagAddr: v.CanAddr is true (implies flagIndir)
// - flagMethod: v is a method value.
// The next five bits give the Kind of the value.
// This repeats typ.Kind() except for method values.
// The remaining 23+ bits give a method number for method values.
// If flag.kind() != Func, code can assume that flagMethod is unset.
// If typ.size > ptrSize, code can assume that flagIndir is set.
When getting the ValueOf something:
// ValueOf returns a new Value initialized to the concrete value
// stored in the interface i. ValueOf(nil) returns the zero Value.
func ValueOf(i interface{}) Value {
[...]
// For an interface value with the noAddr bit set,
// the representation is identical to an empty interface.
eface := *(*emptyInterface)(unsafe.Pointer(&i))
typ := eface.typ
/** Flag is built from the type, then kept separate (my comment) */
fl := flag(typ.Kind()) << flagKindShift
if typ.size > ptrSize {
fl |= flagIndir
}
return Value{typ, unsafe.Pointer(eface.word), fl}
}
And so when you get the kind of a Value (remember it extends its flag):
func (v Value) Kind() Kind {
return v.kind()
}
func (f flag) kind() Kind {
return Kind((f >> flagKindShift) & flagKindMask)
}
While getting the kind of a type: (Type is an interface, usually implemented by *rtype)
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
So although they seem to be equal in most of the cases, v.Kind() is not v.Type().Kind()
The file reflect/value.go states that the relevant field in the implementation of reflect.Value "repeats typ.Kind() except for method values". So, unless the value is a method, value.Kind() and value.Type().Kind() return the same number.

Resources