Casting pointer value expression - go

I'm trying to figure out what this expression does:
(*levelValue)(&level)
I don't understand what is happening, it seems like it dereferencing levelValue first, but not sure why as the type of levelValue is int32
Some context below
import "flag"
type Level int32
type levelValue Level
// LevelFlag defines a Level flag with specified name, default value and
// usage string. The return value is the address of a Level value that stores
// the value of the flag.
func LevelFlag(name string, defaultLevel Level, usage string) *Level {
level := defaultLevel
flag.Var((*levelValue)(&level), name, usage)
return &level
}
func (l *levelValue) Set(s string) error {
return (*Level)(l).UnmarshalText([]byte(s))
}
func (l *levelValue) String() string {
return (*Level)(l).String()
}
Reference

This is a type conversion:
When you define a type like that
type A B
You can convert a variable of type B to type A like that:
b := B
a := A(b)
In your case, the type A is (*levelValue) (The parenthesis are needed to specify that the type is a pointer to a levelValue. And the variable b is &level (A pointer that points to the variable level)

Related

Is there a way to set a pointer struct field to a pointer pointing to the Zero value of that pointer type using reflect?

That was a mouthful of a title, let me explain more. Assuming I have a struct of all pointers (don't know of what type)
type A struct {
S *string
I *int
}
I want to write a function that takes a pointer to that struct and given a fieldName sets that field to a pointer to the Zero/empty value of that pointer. For example:
func setZeroForField(i any, fieldName string) {
// do stuff
}
a := A{}
setZeroForField(&a, "S")
setZeroForField(&a, "I")
// *a.S == ""
// *a.I == 0
Is there any way to do it using reflect? I know how to get the types of the fields of A but I can't use reflect.Indirect because it just returns a Zero value which in this case is a nil pointer, not the empty string or 0.
func setZeroForField(i any, fieldName string) {
rv := reflect.ValueOf(i).Elem()
fv := rv.FieldByName(fieldName)
fv.Set(reflect.New(fv.Type().Elem()))
}
https://go.dev/play/p/7clmztF5uaa

How to get a Protobuf enum value from its string representation?

I can get the string value of a Protobuf enum with this instruction:
str := testPB.Status_ENABLED.String()
How can I perform the inverse operation? (from a string, get the enum element).
The generated code has a map called <EnumName>_value of type map[string]int32. Then you can convert the numerical value to the actual defined type:
num := testPB.Status_value[str]
v := testPB.Status(num)
Consider that if the str value doesn't exist in the map (note that it's case sensitive), the map look-up will return 0. Depending on how you defined your protobuffer, the 0 value might be mapped to a an enum instance that does not have "zero" semantics. This is why it is recommended to map 0 to an "unknown" instance:
enum Status {
UNKNOWN = 0;
ENABLED = 1;
// and so on
}
Which in Go correctly yields a makeshift zero-value if the string representation is effectively unknown:
v := testPB.Status(testPB.Status_value["does_not_exist"])
fmt.Println(v == testPB.Status_UNKNOWN) // true
Go 1.18
With generics, it is possible to write reusable code to construct protobuffer enums from string values:
func Enum[T ~string, PB ~int32](val T, pbmap map[string]int32, dft PB) PB {
v, ok := pbmap[string(val)]
if !ok {
return dft
}
return PB(v)
}
where:
the type parameter T is the string representation, which could also be a type with underlying type string, e.g. type MyEnum string
the argument pbmap is the <EnumName>_value from the generated protobuffer code
the type parameter PB is the protobuffer enum type.
The function above takes a default value of type PB to (obviously) have a fallback in case the string representation is invalid, and also to allow type inference on PB, which otherwise would be used only as a return type.
Usage:
type SomeEnum string
const (
SomeEnumFoo SomeEnum = "FOO"
SomeEnumBar SomeEnum = "BAR"
)
func main() {
foo := SomeEnumFoo
v := Enum(foo, pb.SomeEnum_value, pb.SomeEnum_Foo)
// ^ T ^ map[string]int32 ^ default PB value
// v is type pb.SomeEnum
}

panic: reflect: call of reflect.Value.FieldByName on interface Value

I have a variable of type interface{} and I want to change the value of a field using reflection. How can I do it? Variable must be of type interface{} due to other requirements. If the variable isn't of type interface{} all works, otherwise code throws
reflect: call of reflect.Value.FieldByName on interface Value
my code
package main
import (
"fmt"
"reflect"
)
func main() {
a := struct {
Name string
}{}
// works
reflect.ValueOf(&a).Elem().FieldByName("Name").SetString("Hello")
fmt.Printf("%#v\n", a)
var b interface{}
b = struct {
Name string
}{}
// panics
reflect.ValueOf(&b).Elem().FieldByName("Name").SetString("Hello")
fmt.Printf("%#v\n", b)
}
The application must call Elem() twice to get the struct value:
reflect.ValueOf(&b).Elem().Elem().FieldByName("Name").SetString("Hello")
The first call Elem() dereferences the pointer to interface{}. The second call to Elem() gets the value contained in the interface.
With this change, the panic is reflect.Value.SetString using unaddressable value.
The application cannot set fields directly on the struct value contained in the interface because values contained in an interface are not addressable.
Copy the struct value to a temporary variable, set the field in the temporary variable and copy the temporary variable back to the interface.
var b interface{}
b = struct {
Name string
}{}
// v is the interface{}
v := reflect.ValueOf(&b).Elem()
// Allocate a temporary variable with type of the struct.
// v.Elem() is the vale contained in the interface.
tmp := reflect.New(v.Elem().Type()).Elem()
// Copy the struct value contained in interface to
// the temporary variable.
tmp.Set(v.Elem())
// Set the field.
tmp.FieldByName("Name").SetString("Hello")
// Set the interface to the modified struct value.
v.Set(tmp)
fmt.Printf("%#v\n", b)
Run it on the Go playground.
The interface b is initialized using the value of the anonymous struct, so b contains a copy of the struct, and the values are not addressable. Initialize b using a pointer:
var b interface{}
b = &struct {
Name string
}{}
reflect.ValueOf(b).Elem().FieldByName("Name").SetString("Hello")

Does type assertion change the value in go?

Go newbie here.
I have a map where the key arguments should be []string.
However, if I try to use the value directly arguments := m["arguments"] it doesn't seem to be the right type. When used later to append to another slice with arguments... I get Cannot use 'arguments' (type interface{}) as type []string.
I fixed this by chaning the assignment to a type check arguments, _ := m["arguments"].([]string). That works, but I'm not sure why. Is type assertion doing conversion as well?
The full example is below:
import (
"github.com/fatih/structs"
"strings"
)
var playbookKeyDict = map[string]string{
"Playbook": "",
"Limit" : "--limit",
"ExtraVars" : "--extra-vars",
}
type Playbook struct {
Playbook string `json:"playbook" xml:"playbook" form:"playbook" query:"playbook"`
Limit string `json:"limit" xml:"limit" form:"limit" query:"limit"`
ExtraVars string `json:"extra-vars" xml:"extra-vars" form:"extra-vars" query:"extra-vars"`
Arguments []string `json:"arguments" xml:"arguments" form:"arguments" query:"arguments"`
Args []string
}
func (p *Playbook) formatArgs() {
// is it worth iterating through directly with reflection instead of using structs import?
// https://stackoverflow.com/questions/21246642/iterate-over-string-fields-in-struct
m := structs.Map(p)
// direct assignment has the wrong type?
// arguments := m["arguments"]
arguments, _ := m["arguments"].([]string)
delete(m, "arguments")
for k, v := range m {
// Ignore non-strings and empty strings
if val, ok := v.(string); ok && val != "" {
key := playbookKeyDict[k]
if key == "" {
p.Args = append(p.Args, val)
} else {
p.Args = append(p.Args, playbookKeyDict[k], val)
}
}
}
p.Args = append(p.Args, arguments...)
}
Type assertion is used to get a value wrapped around using interface.
m := structs.Map(p)
Map(v interface{}){}
Map function is actually taking interface as its argument in the case stated. It is wrapping the type which is []string and its underlying value which is slice. The type can be checked using Relection reflect.TypeOf().
func TypeOf(i interface{}) Type
According to Russ Cox blog on Interfaces
Interface values are represented as a two-word pair giving a pointer
to information about the type stored in the interface and a pointer to
the associated data.
As specified in Golang spec
For an expression x of interface type and a type T, the primary
expression
x.(T)
asserts that x is not nil and that the value stored in x is of type T.
The notation x.(T) is called a type assertion.
For the error part:-
Cannot use 'arguments' (type interface{}) as type []string
We first needs to get the underlying value of type []string from interface using type assertion.

how to use a derived type for sync.Map

My goal is to have a custom type the one I could derive and add extra methods, for example, when using a map this works:
package main
import "fmt"
type myMap map[string]string
func (m *myMap) Add() {
_, ok := (*m)["test"]
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
But if want the same with sync.Map how to do it? I am currently trying this: https://play.golang.org/p/8PjpPY-Sjq
package main
import (
"fmt"
"sync"
)
type myMap sync.Map
func (m *myMap) Add() {
_, ok := (*m).Load("test")
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
But get this error:
(*m).Load undefined (type myMap has no field or method Load)
Any ideas?
The Go Programming Language Specification
Struct types
A struct is a sequence of named elements, called fields, each of
which has a name and a type. Field names may be specified explicitly
(IdentifierList) or implicitly (EmbeddedField). Within a struct,
non-blank field names must be unique.
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
A field declared with a type but no explicit field name is called an
embedded field. An embedded field must be specified as a type name T
or as a pointer to a non-interface type name *T, and T itself may not
be a pointer type. The unqualified type name acts as the field name.
A field or method f of an embedded field in a struct x is called
promoted if x.f is a legal selector that denotes that field or method
f.
Promoted fields act like ordinary fields of a struct except that they
cannot be used as field names in composite literals of the struct.
Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S
also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
Use an embedded field of a struct. For example,
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Load(k)
fmt.Println(k, v, ok)
}
Playground: https://play.golang.org/p/YCNeiYVhlT
Output:
true
test 42 true
The Go Programming Language Specification
Selectors
For a primary expression x that is not a package name, the selector
expression
x.f
denotes the field or method f of the value x (or sometimes *x; see
below). The identifier f is called the (field or method) selector; it
must not be the blank identifier. The type of the selector expression
is the type of f. If x is a package name, see the section on qualified
identifiers.
A selector f may denote a field or method f of a type T, or it may
refer to a field or method f of a nested embedded field of T. The
number of embedded fields traversed to reach f is called its depth in
T. The depth of a field or method f declared in T is zero. The depth
of a field or method f declared in an embedded field A in T is the
depth of f in A plus one.
Rule 1:
For a value x of type T or *T where T is not a pointer or interface
type, x.f denotes the field or method at the shallowest depth in T
where there is such an f. If there is not exactly one f with
shallowest depth, the selector expression is illegal.
Sometimes, there is ambiguity in complex cases of nested embedding. If so, specify the full qualifiers explicitly. For example, m.Map.LoadOrStore and x.Map.Load.
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.Map.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Map.Load(k)
fmt.Println(k, v, ok)
}
The line: type myMap sync.Map defines a new type based on an existing type.
According to the Language Specification:
A defined type may have methods associated with it. It does not
inherit any methods bound to the given type
It means, that myMap only inherits the fields of sync.Map (which is a struct) but not it's methods. It doesn't work like class inheritance in other languages.
Specifically, sync.Map does not have any exported fields, so using it to define a new type is pointless.
Instead you should define a struct type that contains sync.Map as a field. Then you'll have access to it's methods. #peterSO's answer shows how to do that.

Resources