Type definition and interface conversion - go

I have tried out the following code:
package main
import (
"fmt"
"sync"
)
type T string
func main() {
var a sync.Map // map[interface{}]interface{}
var c T
// a.Store("a", T("A"))
a.Store("a", "A")
b, _ := a.Load("a")
c = b.(T)
fmt.Println(c)
}
This gets an error of panic: interface conversion: interface {} is string, not main.T.
However, it works if I use the commented line.
Aren't T and string of same underlying types? What's behind this?

This stores a string in the map:
a.Store("a", "A")
This loads the value from the map, but returns an interface that is pointing to the value inserted above, which is a string:
b, _ := a.Load("a")
This will check if b is a T:
c = b.(T)
But b is a string, so the assertion fails.
If you do:
a.Store("a",T("A"))
then the assertion should work, because the type of the value in the map is now a T.

Related

Assert interface to slice of struct

Why am I facing error that first arg to append must be slice after being already asserted interface to a slice of structs?
package main
import (
"fmt"
)
type AccessKeys struct {
AccessKeys interface{}
}
type AccessKey struct {
AccessKeyID string
}
func main() {
var b AccessKey
b.AccessKeyID = "ye"
var bs AccessKeys
bs.AccessKeys = bs.AccessKeys.([]AccessKey) // Assert
bs.AccessKeys = append(bs.AccessKeys, b) // Error: first argument to append must be slice; have interface {}
fmt.Println(bs)
}
https://play.golang.org/p/OfT3i1AbkMe
It cannot work because you try to append AccessKey to type interface{} which is not a slice.
package main
import (
"fmt"
)
type AccessKeys struct {
AccessKeys []interface{}
}
type AccessKey struct {
AccessKeyID string
}
func main() {
var b AccessKey
b.AccessKeyID = "ye"
var bs AccessKeys
bs.AccessKeys = append(bs.AccessKeys, b)
fmt.Println(bs)
}
But in my opinion this is not very idiomatic way to do something, but depends what are you trying to achieve. What I would even replace
AccessKeys []interface{}
with
AccessKeys []AccessKey
Thanks to a kind poster who deleted his comment later.
It doesn't work because AccessKeys interface{} makes AccessKeys an untyped nil type as the zero value for an interface is untyped nil. As Go is a statically typed language, it will give an error at compile time.
If this makes sense, its for the same reason you can't do this in Go:
n := nil
Even if that is fixed, it will fail at runtime while asserting saying panic: interface conversion: interface {} is nil, not []main.AccessKey. Though I am not sure why.

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

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.

Confused by interface embeded in struct in golang

Like code here, when embedding an interface A into struct B, and then set A to aa which is an instance of AA. Both B and AA have element X, when call b.X I just got B.X. How can I get b.AA.X? I know this syntax is wired, but I just want to figure out how var b is stored in the memory, I tried some unsafe syntax, no way to get b.A.X.:
package main
import (
"fmt"
"unsafe"
)
type A interface {
Hello() string
}
type B struct {
A
X string
}
type AA struct {
num int
X string
}
func (aa AA) Hello() string {
return fmt.Sprintf("hello %d from %s", aa.num, aa.X)
}
func main() {
aa := AA{200, "golang"}
b := B{A: aa, X: "python"}
fmt.Println(b.X) // output: python
fmt.Printf("--->%d\n", ((*AA)(unsafe.Pointer(&b.A)).num)) // output: --->17667104
fmt.Printf("===>%+v\n", b.A) // output: ===>{num:200 X:golang}
}
Embedded fields are accessed by their type name, and fields of an interface are only accessible by asserting the underlying type, so b.A.(AA).X will get you field X of the underlying AA that's in b.A. But if you're needing to access fields, you probably shouldn't be embedding the interface type anyway, you should be embedding the concrete type.

Get Receiver Type and Method name from just a reference of function in Go

Given a code setup like this,
package main
import (
"fmt"
"reflect"
"runtime/debug"
)
type A struct{}
func (o *A) B() error {
debug.PrintStack()
return nil
}
func main() {
a := &A{}
b := a.B
// Note that if run b(), it can print the stack and show the info
// "(*A).B-fm" and "(*A).B"
m := reflect.ValueOf(b)
fmt.Println(m.Type().String())
}
Is it possible to get the information of b's receiver type A and B as a method? How if possible?
Note that b is value of method B of type A.
(Possible use scenario, generating a constant unique API ID based on only a reference like b, by forming a string like (*A).B. It's used to build a debug tool without a need to change existing code.)
update:
This will do the work.
fmt.Println(runtime.FuncForPC(m.Pointer()).Name())
Credits to this awesome article,

What's the difference between new(Struct) and &Struct{} in Go?

They seem to be the same:
package main
import "fmt"
type S struct {
i int
}
func main() {
var s1 *S = new(S)
fmt.Println(s1)
var s2 *S = &S{}
fmt.Println(s2) // Prints the same thing.
}
Update:
Hm. I just realized that there's no obvious way to initialize S.i using new. Is there a way to do that? new(S{i:1}) does not seem to work :/
From Effective Go:
As a limiting case, if a composite literal contains no fields at all, it creates a zero value for the type. The expressions new(File) and &File{} are equivalent.
Not only do they give the same resulting value, but if we allocate something both ways and look at their values...
// Adapted from http://tour.golang.org/#30
package main
import "fmt"
type Vertex struct {
X, Y int
}
func main() {
v := &Vertex{}
v2 := new(Vertex)
fmt.Printf("%p %p", v, v2)
}
...we'll see that they are in fact allocated in consecutive memory slots. Typical output: 0x10328100 0x10328108. I'm not sure if this is an implementation detail or part of the specification, but it does demonstrate that they're both being allocated from the same pool.
Play around with the code here.
As for initializing with new, according to the language spec: The built-in function new takes a type T and returns a value of type *T. The memory [pointed to] is initialized as described in the section on initial values. Because functions in go can't be overloaded, and this isn't a variadic function, there's no way to pass in any initialization data. Instead, go will initialize it with whatever version of 0 makes sense for the type and any member fields, as appropriate.
Case 1: package main
import (
"fmt"
)
type Drink struct {
Name string
Flavour string
}
func main() {
a := new(Drink)
a.Name = "Maaza"
a.Flavour = "Mango"
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Frooti"
fmt.Println(a.Name)
}//This will output Frooti for a.Name, even though the addresses for a and b are different.
Case 2:
package main
import (
"fmt"
)
type Drink struct {
Name string
Flavour string
}
func main() {
a := Drink{
Name: "Maaza",
Flavour: "Mango",
}
b := a
fmt.Println(&a)
fmt.Println(&b)
b.Name = "Froti"
fmt.Println(a.Name)
}//This will output Maaza for a.Name. To get Frooti in this case assign b:=&a.

Resources