How to access unexported struct fields - go

Is there a way to use reflect to access unexported fields in Go 1.8?
This no longer seems to work: https://stackoverflow.com/a/17982725/555493
Note that reflect.DeepEqual works just fine (that is, it can access unexported fields) but I can't make heads or tails of that function. Here's a go playarea that shows it in action: https://play.golang.org/p/vyEvay6eVG. The src code is below
import (
"fmt"
"reflect"
)
type Foo struct {
private string
}
func main() {
x := Foo{"hello"}
y := Foo{"goodbye"}
z := Foo{"hello"}
fmt.Println(reflect.DeepEqual(x,y)) //false
fmt.Println(reflect.DeepEqual(x,z)) //true
}

If the struct is addressable, you can use unsafe.Pointer to access the field (read or write) it, like this:
rs := reflect.ValueOf(&MyStruct).Elem()
rf := rs.Field(n)
// rf can't be read or set.
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read and set.
See full example on the playground.
This use of unsafe.Pointer is valid according to the documentation and running go vet returns no errors.
If the struct is not addressable this trick won't work, but you can create an addressable copy like this:
rs = reflect.ValueOf(MyStruct)
rs2 := reflect.New(rs.Type()).Elem()
rs2.Set(rs)
rf = rs2.Field(0)
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read. Setting will succeed but only affects the temporary copy.
See full example on the playground.

Based on cpcallen's work:
import (
"reflect"
"unsafe"
)
func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}
func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}
reflect.NewAt might be confusing to read at first. It returns a reflect.Value representing a pointer to a value of the specified field.Type(), using unsafe.Pointer(field.UnsafeAddr()) as that pointer. In this context reflect.NewAt is different than reflect.New, which would return a pointer to a freshly initialized value.
Example:
type Foo struct {
unexportedField string
}
GetUnexportedField(reflect.ValueOf(&Foo{}).Elem().FieldByName("unexportedField"))
https://play.golang.org/p/IgjlQPYdKFR

reflect.DeepEqual() can do it because it has access to unexported features of the reflect package, in this case namely for the valueInterface() function, which takes a safe argument, which denies access to unexported field values via the Value.Interface() method if safe=true. reflect.DeepEqual() will (might) call that passing safe=false.
You can still do it, but you cannot use Value.Interface() for unexported fields. Instead you have to use type-specific methods, such as Value.String() for string, Value.Float() for floats, Value.Int() for ints etc. These will return you a copy of the value (which is enough to inspect it), but will not allow you to modify the field's value (which might be "partly" possible if Value.Interface() would work and the field type would be a pointer type).
If a field happens to be an interface type, you may use Value.Elem() to get to the value contained / wrapped by the interface value.
To demonstrate:
type Foo struct {
s string
i int
j interface{}
}
func main() {
x := Foo{"hello", 2, 3.0}
v := reflect.ValueOf(x)
s := v.FieldByName("s")
fmt.Printf("%T %v\n", s.String(), s.String())
i := v.FieldByName("i")
fmt.Printf("%T %v\n", i.Int(), i.Int())
j := v.FieldByName("j").Elem()
fmt.Printf("%T %v\n", j.Float(), j.Float())
}
Output (try it on the Go Playground):
string hello
int64 2
float64 3

package main
import (
"fmt"
"reflect"
"strings"
"unsafe"
)
type Person1 struct {
W3ID string
Name string
}
type Address1 struct {
city string
country string
}
type User1 struct {
name string
age int
address Address1
manager Person1
developer Person1
tech Person1
}
func showDetails(load, email interface{}) {
if reflect.ValueOf(load).Kind() == reflect.Struct {
typ := reflect.TypeOf(load)
value := reflect.ValueOf(load)
//#1 For struct, not addressable create a copy With Element.
value2 := reflect.New(value.Type()).Elem()
//#2 Value2 is addressable and can be set
value2.Set(value)
for i := 0; i < typ.NumField(); i++ {
if value.Field(i).Kind() == reflect.Struct {
rf := value2.Field(i)
/* #nosec G103 */
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
irf := rf.Interface()
typrf := reflect.TypeOf(irf)
nameP := typrf.String()
if strings.Contains(nameP, "Person") {
//fmt.Println(nameP, "FOUND !!!!!!! ")
for j := 0; j < typrf.NumField(); j++ {
re := rf.Field(j)
nameW := typrf.Field(j).Name
if strings.Contains(nameW, "W3ID") {
valueW := re.Interface()
fetchEmail := valueW.(string)
if fetchEmail == email {
fmt.Println(fetchEmail, " MATCH!!!!")
}
}
}
}
showDetails(irf, email)
} else {
// fmt.Printf("%d.Type:%T || Value:%#v\n",
// (i + 1), value.Field(i), value.Field(i))
}
}
}
}
func main() {
iD := "tsumi#in.org.com"
load := User1{
name: "John Doe",
age: 34,
address: Address1{
city: "New York",
country: "USA",
},
manager: Person1{
W3ID: "jBult#in.org.com",
Name: "Bualt",
},
developer: Person1{
W3ID: "tsumi#in.org.com",
Name: "Sumi",
},
tech: Person1{
W3ID: "lPaul#in.org.com",
Name: "Paul",
},
}
showDetails(load, iD)
}

Related

How do I get at the contents of a private reflect.Value in go?

I'm trying to make a general purpose debug printer for complex data types because %v has a tendency to just print pointer values rather than what they point at. I've got it working with everything up until I have to deal with structs containing reflect.Value fields.
The following demo code runs without error: (https://play.golang.org/p/qvdRKc40R8k)
package main
import (
"fmt"
"reflect"
)
type MyStruct struct {
i int
R reflect.Value
}
func printContents(value interface{}) {
// Omitted: check if value is actually a struct
rv := reflect.ValueOf(value)
for i := 0; i < rv.NumField(); i++ {
fmt.Printf("%v: ", rv.Type().Field(i).Name)
field := rv.Field(i)
switch field.Kind() {
case reflect.Int:
fmt.Printf("%v", field.Int())
case reflect.Struct:
// Omitted: check if field is actually a reflect.Value to an int
fmt.Printf("reflect.Value(%v)", field.Interface().(reflect.Value).Int())
}
fmt.Printf("\n")
}
}
func main() {
printContents(MyStruct{123, reflect.ValueOf(456)})
}
This prints:
i: 123
R: reflect.Value(456)
However, if I change MyStruct's R field name to r, it fails:
panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
Of course, it's rightly failing because this would otherwise be a way to get an unexported field into proper goland, which is a no-no.
But this leaves me in a quandry: How can I gain access to whatever the unexported reflect.Value refers to without using Interface() so that I can walk its contents and print? I've looked through the reflect documentation and haven't found anything that looks helpful...
After some digging, I've found a solution:
The only way to get at the inner reflect.Value is to call Interface() and type assert it, but this will panic if called on an unexported field. The only way around this is to use the unsafe package to clear the read-only flag so that the Interface() method will think it's exported when it's not (basically, we subvert the type system):
type flag uintptr // reflect/value.go:flag
type flagROTester struct {
A int
a int // reflect/value.go:flagStickyRO
int // reflect/value.go:flagEmbedRO
// Note: flagRO = flagStickyRO | flagEmbedRO
}
var flagOffset uintptr
var maskFlagRO flag
var hasExpectedReflectStruct bool
func initUnsafe() {
if field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag"); ok {
flagOffset = field.Offset
} else {
log.Println("go-describe: exposeInterface() is disabled because the " +
"reflect.Value struct no longer has a flag field. Please open an " +
"issue at https://github.com/kstenerud/go-describe/issues")
hasExpectedReflectStruct = false
return
}
rv := reflect.ValueOf(flagROTester{})
getFlag := func(v reflect.Value, name string) flag {
return flag(reflect.ValueOf(v.FieldByName(name)).FieldByName("flag").Uint())
}
flagRO := (getFlag(rv, "a") | getFlag(rv, "int")) ^ getFlag(rv, "A")
maskFlagRO = ^flagRO
if flagRO == 0 {
log.Println("go-describe: exposeInterface() is disabled because the " +
"reflect flag type no longer has a flagEmbedRO or flagStickyRO bit. " +
"Please open an issue at https://github.com/kstenerud/go-describe/issues")
hasExpectedReflectStruct = false
return
}
hasExpectedReflectStruct = true
}
func canExposeInterface() bool {
return hasExpectedReflectStruct
}
func exposeInterface(v reflect.Value) interface{} {
pFlag := (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(&v)) + flagOffset))
*pFlag &= maskFlagRO
return v.Interface()
}
There are caveats, in that unsafe isn't allowed or desirable in all environments, not to mention that subverting the type system is rarely the right thing to do. It's recommended that you make such code conditional on build tags, and include a safe alternative.

reflect runtime error: call of reflect.flag.mustBeAssignable on zero Value

I'm testing this code snippet on go playground, I aim to use reflect to get fields from one object, and then set value to another object
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"testaaa"`
B string `json:"bbb" test:"testbbb"`
}
type newT struct {
AA int
BB string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("newT")
tValue := tv.Field(i)
newTValue.Elem().FieldByName(newTTag).Set(tValue)
}
fmt.Println(newT)
}
And it gives a very strange error:
panic: reflect: call of reflect.flag.mustBeAssignable on zero Value
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x0, 0x0)
/usr/local/go/src/reflect/value.go:240 +0xe0
reflect.flag.mustBeAssignable(...)
/usr/local/go/src/reflect/value.go:234
reflect.Value.Set(0x0, 0x0, 0x0, 0x100f80, 0x40a0f0, 0x82)
/usr/local/go/src/reflect/value.go:1531 +0x40
main.main()
/tmp/sandbox166479609/prog.go:32 +0x400
Program exited: status 2.
How to fix it?
It is as error call of reflect.flag.mustBeAssignable on zero Value says , newTValue.Elem().FieldByName(newTTag).CanSet() returns false in your your code and according to documentation
Set assigns x to the value v. It panics if CanSet returns false. As in Go, x's value must be assignable to v's type.
This is corrected code that takes fields from one Object and assigns value to another one.
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
type newT struct {
AA int
BB string
Testaaa string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
fmt.Println(newT)
}
First:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
Each step here iterates through the fields of your instance of type T. So the fields will be A—or rather, the field descriptor whose Name is A and which describes an int with its json and test tags—and then B (with the same picky details if we go any further).
Since both field descriptors have only two Get-able items, you probably meant to use Get("test"), as in Guarav Dhiman's answer.
If you do that, though, the result is "testaaa" when you are on field A and "testbbb" when you are on field B. If we annotate Guarav's code a bit more:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
fmt.Printf("newTTag = %#v\n", newTTag)
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
fmt.Printf("newTfield = %#v\n", newTfield)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
we will see this output:
newTTag = "testaaa"
newTfield = <invalid reflect.Value>
newTTag = "testbbb"
newTfield = <invalid reflect.Value>
What we need is to make the test string in each tag name the field in the newT type:
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
(Guarav actually already did this but did not mention it.) Now the program produces what (presumably) you intended:
&{123 hello}
The complete program, with commented-out tracing, is here.

How to dynamically create a struct with one less property?

Is there a way to copy a generic struct (i.e. a struct whose property names are unknown) and skip a single, known property?
Here is what I know:
The parameter to my function--I will call the parameter myData-- is of type interface{}.
myData is a struct.
myData has a known property path.
myData has anywhere from 0 to 6 or so other properties, none of which are known a priori.
Once I remove that path property, then the “leftover” is one of say 30 possible struct types.
So I want to strip path out of myData (or more accurately make a copy that omits path) so that various bits of generated code that try to coerce the struct to one of its possible types will be able to succeed.
I have found examples of copying a struct by reflection, but they typically create an empty struct of the same underlying type, then fill it in. So is it even possible to delete a property as I have outlined...?
You can use reflect.StructOf to dynamically create structs from a list of fields.
package main
import (
"fmt"
"reflect"
)
type A struct {
Foo string
Bar int
Baz bool // to be skipped
}
type B struct {
Foo string
Bar int
}
func main() {
av := reflect.ValueOf(A{"hello", 123, true})
fields := make([]reflect.StructField, 0)
values := make([]reflect.Value, 0)
for i := 0; i < av.NumField(); i++ {
f := av.Type().Field(i)
if f.Name != "Baz" {
fields = append(fields, f)
values = append(values, av.Field(i))
}
}
typ := reflect.StructOf(fields)
val := reflect.New(typ).Elem()
for i := 0; i < len(fields); i++ {
val.Field(i).Set(values[i])
}
btyp := reflect.TypeOf(B{})
bval := val.Convert(btyp)
b, ok := bval.Interface().(B)
fmt.Println(b, ok)
}

Appending to go lang slice using reflection

For some reason, it appears that adding new element to slice using reflection doesn't update slice itself. This is the code to demonstrate:
package main
import (
"fmt"
"reflect"
)
func appendToSlice(arrPtr interface{}) {
valuePtr := reflect.ValueOf(arrPtr)
value := valuePtr.Elem()
value = reflect.Append(value, reflect.ValueOf(55))
fmt.Println(value.Len()) // prints 1
}
func main() {
arr := []int{}
appendToSlice(&arr)
fmt.Println(len(arr)) // prints 0
}
Playground link : https://play.golang.org/p/j3532H_mUL
Is there something I'm missing here?
reflect.Append works like append in that it returns a new slice value.
You are assigning this value to the value variable in the appendToSlice function, which replaces the previous reflect.Value, but does not update the original argument.
To make it more clear what's happening, take the equivalent function to your example without reflection:
func appendToSlice(arrPtr *[]int) {
value := *arrPtr
value = append(value, 55)
fmt.Println(len(value))
}
What you need to use is the Value.Set method to update the original value:
func appendToSlice(arrPtr interface{}) {
valuePtr := reflect.ValueOf(arrPtr)
value := valuePtr.Elem()
value.Set(reflect.Append(value, reflect.ValueOf(55)))
fmt.Println(value.Len())
}
https://play.golang.org/p/Nhabg31Sju
package main
import "fmt"
import "reflect"
type Foo struct {
Name string
}
func main() {
_type := []Foo{}
fmt.Printf("_type: v(%v) T(%T)\n", _type, _type)
reflection := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(_type).Elem()), 0, 0)
reflectionValue := reflect.New(reflection.Type())
reflectionValue.Elem().Set(reflection)
slicePtr := reflect.ValueOf(reflectionValue.Interface())
sliceValuePtr := slicePtr.Elem()
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"a"})))
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"b"})))
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(Foo{"c"})))
values := []Foo{Foo{"d"}, Foo{"e"}}
for _, val := range values {
sliceValuePtr.Set(reflect.Append(sliceValuePtr, reflect.ValueOf(val)))
}
result := sliceValuePtr.Interface()
fmt.Printf("result: %T = (%v)\n", result, result)
}
take a look at: https://play.golang.org/p/vXOqTVSEleO

How to find the type of an object in Go?

How do I find the type of an object in Go? In Python, I just use typeof to fetch the type of object. Similarly in Go, is there a way to implement the same ?
Here is the container from which I am iterating:
for e := dlist.Front(); e != nil; e = e.Next() {
lines := e.Value
fmt.Printf(reflect.TypeOf(lines))
}
I am not able to get the type of the object lines in this case which is an array of strings.
The Go reflection package has methods for inspecting the type of variables.
The following snippet will print out the reflection type of a string, integer and float.
package main
import (
"fmt"
"reflect"
)
func main() {
tst := "string"
tst2 := 10
tst3 := 1.2
fmt.Println(reflect.TypeOf(tst))
fmt.Println(reflect.TypeOf(tst2))
fmt.Println(reflect.TypeOf(tst3))
}
Output:
string
int
float64
see: http://play.golang.org/p/XQMcUVsOja to view it in action.
More documentation here: http://golang.org/pkg/reflect/#Type
I found 3 ways to return a variable's type at runtime:
Using string formatting
func typeof(v interface{}) string {
return fmt.Sprintf("%T", v)
}
Using reflect package
func typeof(v interface{}) string {
return reflect.TypeOf(v).String()
}
Using type switch
func typeof(v interface{}) string {
switch v.(type) {
case int:
return "int"
case float64:
return "float64"
//... etc
default:
return "unknown"
}
}
Every method has a different best use case:
string formatting - short and low footprint (not necessary to import reflect package)
reflect package - when need more details about the type we have access to the full reflection capabilities
type switch - allows grouping types, for example recognize all int32, int64, uint32, uint64 types as "int"
Use the reflect package:
Package reflect implements run-time reflection, allowing a program to
manipulate objects with arbitrary types. The typical use is to take a
value with static type interface{} and extract its dynamic type
information by calling TypeOf, which returns a Type.
package main
import (
"fmt"
"reflect"
)
func main() {
b := true
s := ""
n := 1
f := 1.0
a := []string{"foo", "bar", "baz"}
fmt.Println(reflect.TypeOf(b))
fmt.Println(reflect.TypeOf(s))
fmt.Println(reflect.TypeOf(n))
fmt.Println(reflect.TypeOf(f))
fmt.Println(reflect.TypeOf(a))
}
Produces:
bool
string
int
float64
[]string
Playground
Example using ValueOf(i interface{}).Kind():
package main
import (
"fmt"
"reflect"
)
func main() {
b := true
s := ""
n := 1
f := 1.0
a := []string{"foo", "bar", "baz"}
fmt.Println(reflect.ValueOf(b).Kind())
fmt.Println(reflect.ValueOf(s).Kind())
fmt.Println(reflect.ValueOf(n).Kind())
fmt.Println(reflect.ValueOf(f).Kind())
fmt.Println(reflect.ValueOf(a).Index(0).Kind()) // For slices and strings
}
Produces:
bool
string
int
float64
string
Playground
To get a string representation:
From http://golang.org/pkg/fmt/
%T a Go-syntax representation of the type of the value
package main
import "fmt"
func main(){
types := []interface{} {"a",6,6.0,true}
for _,v := range types{
fmt.Printf("%T\n",v)
}
}
Outputs:
string
int
float64
bool
I would stay away from the reflect. package. Instead use %T
package main
import (
"fmt"
)
func main() {
b := true
s := ""
n := 1
f := 1.0
a := []string{"foo", "bar", "baz"}
fmt.Printf("%T\n", b)
fmt.Printf("%T\n", s)
fmt.Printf("%T\n", n)
fmt.Printf("%T\n", f)
fmt.Printf("%T\n", a)
}
Best way is using reflection concept in Google.
reflect.TypeOf gives type along with the package name
reflect.TypeOf().Kind() gives underlining type
To be short, please use fmt.Printf("%T", var1) or its other variants in the fmt package.
If we have this variables:
var counter int = 5
var message string = "Hello"
var factor float32 = 4.2
var enabled bool = false
1: fmt.Printf %T format : to use this feature you should import "fmt"
fmt.Printf("%T \n",factor ) // factor type: float32
2: reflect.TypeOf function : to use this feature you should import "reflect"
fmt.Println(reflect.TypeOf(enabled)) // enabled type: bool
3: reflect.ValueOf(X).Kind() : to use this feature you should import "reflect"
fmt.Println(reflect.ValueOf(counter).Kind()) // counter type: int
You can check the type of any variable/instance at runtime either using the "reflect" packages TypeOf function or by using fmt.Printf():
package main
import (
"fmt"
"reflect"
)
func main() {
value1 := "Have a Good Day"
value2 := 50
value3 := 50.78
fmt.Println(reflect.TypeOf(value1 ))
fmt.Println(reflect.TypeOf(value2))
fmt.Println(reflect.TypeOf(value3))
fmt.Printf("%T",value1)
fmt.Printf("%T",value2)
fmt.Printf("%T",value3)
}
To get the type of fields in struct
package main
import (
"fmt"
"reflect"
)
type testObject struct {
Name string
Age int
Height float64
}
func main() {
tstObj := testObject{Name: "yog prakash", Age: 24, Height: 5.6}
val := reflect.ValueOf(&tstObj).Elem()
typeOfTstObj := val.Type()
for i := 0; i < val.NumField(); i++ {
fieldType := val.Field(i)
fmt.Printf("object field %d key=%s value=%v type=%s \n",
i, typeOfTstObj.Field(i).Name, fieldType.Interface(),
fieldType.Type())
}
}
Output
object field 0 key=Name value=yog prakash type=string
object field 1 key=Age value=24 type=int
object field 2 key=Height value=5.6 type=float64
See in IDE https://play.golang.org/p/bwIpYnBQiE
You can use: interface{}..(type) as in this playground
package main
import "fmt"
func main(){
types := []interface{} {"a",6,6.0,true}
for _,v := range types{
fmt.Printf("%T\n",v)
switch v.(type) {
case int:
fmt.Printf("Twice %v is %v\n", v, v.(int) * 2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v.(string)))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
}
For arrays and slices use Type.Elem():
a := []string{"foo", "bar", "baz"}
fmt.Println(reflect.TypeOf(a).Elem())
I have organized the following.
fmt %T : a Go-syntax representation of the type of the value
reflect.TypeOf.String()
reflect.TypeOf.Kind()
type assertions
Example
package _test
import (
"fmt"
"reflect"
"testing"
)
func TestType(t *testing.T) {
type Person struct {
name string
}
var i interface{}
i = &Person{"Carson"}
for idx, d := range []struct {
actual interface{}
expected interface{}
}{
{fmt.Sprintf("%T", "Hello") == "string", true},
{reflect.TypeOf("string").String() == "string", true},
{reflect.TypeOf("string").Kind() == reflect.String, true},
{reflect.TypeOf(10).String() == "int", true},
{reflect.TypeOf(10).Kind() == reflect.Int, true},
{fmt.Sprintf("%T", 1.2) == "float64", true},
{reflect.TypeOf(1.2).String() == "float64", true},
{reflect.TypeOf(1.2).Kind() == reflect.Float64, true},
{reflect.TypeOf([]byte{3}).String() == "[]uint8", true},
{reflect.TypeOf([]byte{3}).Kind() == reflect.Slice, true},
{reflect.TypeOf([]int8{3}).String() == "[]int8", true},
{reflect.TypeOf([]int8{3}).Kind() == reflect.Slice, true},
{reflect.TypeOf(Person{"carson"}).Kind() == reflect.Struct, true},
{reflect.TypeOf(&Person{"carson"}).Kind() == reflect.Ptr, true},
{fmt.Sprintf("%v", i.(*Person)) == "&{Carson}", true},
{fmt.Sprintf("%+v", i.(*Person)) == "&{name:Carson}", true},
} {
if d.actual != d.expected {
t.Fatalf("%d | %s", idx, d.actual)
}
}
}
go playground
In case if you want to detect the type within if expression:
if str, ok := myvar.(string); ok {
print("It's a string")
}
Or without type assertion (may produce errors):
if reflect.TypeOf(myvar).String() == "string" {
print("It's a string")
}
you can use reflect.TypeOf.
basic type(e.g.: int, string): it will return its name (e.g.: int, string)
struct: it will return something in the format <package name>.<struct name> (e.g.: main.test)
reflect package comes to rescue:
reflect.TypeOf(obj).String()
Check this demo

Resources