Anonymous type declaration works differently via "var" vs ":=" - go

While declaring a variable with anonymous type in Go, I'm seeing var v versus v:= syntaxes work differently. Imagine we're declaring an empty anonymous struct type instance and assign it to a variable.
This works:
func main() {
var v struct {}
_ = v
But this does not:
func main() {
t := struct{}
_ = t
}
compiling this gives the following error (https://play.golang.org/p/MgbttbBVmYE):
prog.go:8:7: type struct {} is not an expression
Why is this the case?

var v struct{} gives v type struct{} but doesn't explicitly set a value, so it gets the zero value {}.
t := struct{} isn't a complete expression. You'd need t := struct{}{} to create t with type struct {} and give it the value {}.
In other words, struct{} is a type, but creating t with := needs a value, not just a type on the right side. struct{}{} is how you write the literal form of an anonymous empty struct.

Related

Why can't i pass this pointer to other function as an argument in go?

I'm just learning GO (with javascript background)
So, i use this excelize package to create excel document using go.
Here's my code:
package main
import (
"fmt"
"github.com/360EntSecGroup-Skylar/excelize"
)
func main() {
f := excelize.NewFile()
create(f)
}
func create(f *int) {
fmt.Println(&f)
}
It's giving me an error cannot use f (type *excelize.File) as type *int in argument to create
Is there anything wrong with my code ?
I'm pretty bad with this whole pointer things, but i have to learn go in 2 weeks.
I also put my code in this GO playground site just in case someone want to test it.
create() expects a value of type *int, that is, a pointer to int. f in main() is of type *excelize.File, that is, a pointer to excelize.File.
The value you pass to create() must be assignable to the type of the parameter, and *excelize.File is not assignable to *int. Details: Spec: Calls.
For example, a value of type *int is assignable to the param of create(), so this is valid:
var i int
create(&i) // i is of type int, so &i is of type *int
Or this:
j := new(int) // j is of type *int
create(j)
If you want your create() function to accept a value of any type, use the empty interface: interface{}
func create(f interface{}) {
fmt.Println(f)
}
Then passing f from main() (or any other value) will be valid:
f := excelize.NewFile()
create(f)

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.

Convert array to interface{} to slice, but the result can not use len() and other method

I tried :
var a [100]int
func fun1(src interface{}) interface{} {
src, _ = src.([100]int) // changed []int to [100]int
fmt.Println(reflect.TypeOf(src)) // result: []int
dest := make([]int, len(src))
return dest
}
there is an error:
message: 'invalid argument src (type interface {}) for len'
But if I redefine a variable:
var a [100]int
func fun1(src interface{}) interface{} {
slice_src, _ := src.([100]int) //changed []int to [100]int
fmt.Println(reflect.TypeOf(slice_src)) // result: []int
dest := make([]int, len(slice_src))
return dest
}
it will be ok.
why reflect.TypeOf(src) will print []int after I used src.([]int) but error shows src is still interface{} ?
I have checked this convert interface{} to int, but I still don't understand how to use correct conversion.
There is another question:
I changed the []int to [100]int since the type assertion before will return [] and false.
But if I don't know the type of a, how can I use type assertion to transfer an array (like[99]int) as a interface{} to function and return slice ([]int)?
when you first declare src, in fun1(src interface{}) you are making a variable of type interface. Which, of course cannot have len called on it.
The reason reflect.TypeOf says []int is due to how TypeOf works.
It takes an interface{} and tells you the type of the thing in the interface{}
so, in the first example, you already had an interface
and in the second example, go automatically created an interface{} instance to hold your []int slice.
Quoting dynamic type from Variables :
The static type (or just type) of a variable is the type given in its declaration, the type provided in the new call or composite literal, or the type of an element of a structured variable. Variables of interface type also have a distinct dynamic type, which is the concrete type of the value assigned to the variable at run time (unless the value is the predeclared identifier nil, which has no type). The dynamic type may vary during execution but values stored in interface variables are always assignable to the static type of the variable.
In the first example, src has a dynamic type. Value of the src will be of type []int during execution but eventually, type will be interface since it is dynamic type & it was of type interface at the time of declaration. Hence, you need to change variable src to the new variable during type assertion.
Similar to what you did in second example: slice_src, _ := src.([]int)
You can not even do src, _ := src.([]int) as you will end up with error no new variables on left side of :=
There is a type switch method using reflect.TypeOf() : golang type assertion using reflect.Typeof()
and
How to get the reflect.Type of an interface?
Quote How to get the reflect.Type of an interface? :
You can't. Type assertions allow you to take advantage of the static type checking that the language gives you even if you have an interface, whose type isn't statically checked. It basically works something like this:
You have some statically typed variable s, which has type t. The compiler enforces the guarantee that s always has type t by refusing to compile if you ever try to use s as if it were a different type, since that would break the guarantee.

Resources