Name of a struct to a string - go

How do I print the name of the type of a struct, i.e. so I can include it in a print statement, i.e. something like
type MyStruct struct { ... }
func main() {
fmt.Println(MyStruct.className())
}
If this is possible, would it be considered a slow operation? (i.e. reflection)

For example,
package main
import "fmt"
type MyStruct struct{}
func main() {
fmt.Printf("%T\n", MyStruct{})
}
Output:
main.MyStruct
The fmt %T print verb gives a Go-syntax representation of the type of the value.
The Go fmt package uses the reflect package for run-time reflection.

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.

Implicit type with struct of slices

If I have a file like this:
package main
import "fmt"
type Language struct {
Example []string
Link []string
}
func main() {
o := Language{
{".go", "go.ps1"},
{"golang.org", "go.dev"},
}
fmt.Println(o)
}
I get this result:
missing type in composite literal
I found I can resolve like this:
[]string{".go", "go.ps1"},
[]string{"golang.org", "go.dev"},
but is that strictly required? I would think Go would know the type of each
property based on the struct definition.
The problem here is not that the compiler doesn't know the type, it is that the syntax for a composite literal requires the type:
https://golang.org/ref/spec#Composite_literals
A string array literal is []string{"a","b",","c"}, not {"a","b","c"}.
You need field in struct definition, like this
o := Language{
Example: []string{".go", "go.ps1"},
Link: []string{"golang.org", "go.dev"},
}
fmt.Println(o)

Printf function show struct differently

I am using compile function of regex package which returns pointer of Regexp struct and passing struct in printf function shows me only string not whole struct.
package main
import (
"fmt"
"regexp"
)
func main() {
reg, _ := regexp.Compile(`[0-9a-f]+`)
fmt.Printf("%+v \n", reg)
}
// Output
[0-9a-f]+
But when I created my own struct and initialising with some value and print it then it shows full struct. I am not understanding the concept here.
package main
import (
"fmt"
)
type Exp struct {
a string
b int
}
func main() {
x := &Exp{"akash", 12}
fmt.Printf("%+v \n", x)
}
// Output: &{akash 12}
The regexp.Regexp type implements the fmt.Stringer interface, which is the default verb used in the fmt.Print* methods.
This means that it calls reg.String() when formatting in your first example.
In your second example, your custom type Exp, has no such method, so it uses default Go-formatting of the struct.

How to set the composite field of a struct field by name in Go?

I have a struct with one of it's fields being another struct and I would like to access this struct by name (as a parameter). I followed Using reflect, how do you set the value of a struct field? and it works for basic type but not for composite types.
package main
import (
"fmt"
"reflect"
)
type PntInt struct {
p *int64
}
type Foo struct {
X int64
Px PntInt
}
func main() {
foo := Foo{}
fmt.Println(foo)
i := int64(8)
Pi := PntInt{&i}
reflect.ValueOf(&foo).Elem().FieldByName("X").SetInt(i)
reflect.ValueOf(&foo).Elem().FieldByName("Px").Set(Pi)
fmt.Println(foo)
}
setting the integer works but trying to set "Px" fails with the error
./prog.go:25:52: cannot use Pi (type PntInt) as type reflect.Value in argument to reflect.ValueOf(&foo).Elem().FieldByName("Px").Set
You want to use a Value:
reflect.ValueOf(&foo).Elem().FieldByName("Px").Set(reflect.ValueOf(Pi))
Here it is running on the Go playground

How to get a pointer of an interface

It's hard to explain, but how I can get a pointer of a something that implements some interface?
Consider the code below:
package main
import (
"fmt"
"unsafe"
)
type Interface interface {
Example()
}
type StructThatImplementsInterface struct {
}
func (i *StructThatImplementsInterface) Example() {
}
type StructThatHasInterface struct {
i Interface
}
func main() {
sameInterface := &StructThatImplementsInterface{}
struct1 := StructThatHasInterface{i: sameInterface}
struct2 := StructThatHasInterface{i: sameInterface}
TheProblemIsHere(&struct1)
TheProblemIsHere(&struct2)
}
func TheProblemIsHere(s *StructThatHasInterface) {
fmt.Printf("Pointer by Printf: %p \n", s.i)
fmt.Printf("Pointer by Usafe: %v \n", unsafe.Pointer(&s.i))
}
https://play.golang.org/p/HoC5_BBeswA
The result will be:
Pointer by Printf: 0x40c138
Pointer by Usafe: 0x40c140
Pointer by Printf: 0x40c138
Pointer by Usafe: 0x40c148
Notice that the Printf gets the same value (because both StructThatHasInterface uses the same sameInterface). However, the unsafe.Pointer() returns distinct values.
How can I get the same result of Printf without use fmt, and reflect if possible?
In the current version of Go, an interface value is two words long. The concrete value or a pointer to the concrete value is stored in the second word. Use the following code to get the second word as a uintptr:
u := (*[2]uintptr)(unsafe.Pointer(&s.i))[1]
This code is unsafe and is not guaranteed to work in future.
The supported way to get the pointer is:
u := reflect.ValueOf(s.i).Pointer()

Resources