package main import ( "errors" "reflect" "strconv" "unsafe" ) type ( myint int myslice []byte myslice2 []myint mychan chan int myptr *int point struct { X int16 Y int16 } mystruct struct { n int `foo:"bar"` some point "some\x00tag" zero struct{} buf []byte Buf []byte } linkedList struct { next *linkedList `description:"chain"` foo int } selfref struct { x *selfref } ) var ( errorValue = errors.New("test error") errorType = reflect.TypeOf((*error)(nil)).Elem() stringerType = reflect.TypeOf((*interface { String() string })(nil)).Elem() ) func main() { println("matching types") println(reflect.TypeOf(int(3)) == reflect.TypeOf(int(5))) println(reflect.TypeOf(int(3)) == reflect.TypeOf(uint(5))) println(reflect.TypeOf(myint(3)) == reflect.TypeOf(int(5))) println(reflect.TypeOf(myslice{}) == reflect.TypeOf([]byte{})) println(reflect.TypeOf(myslice2{}) == reflect.TypeOf([]myint{})) println(reflect.TypeOf(myslice2{}) == reflect.TypeOf([]int{})) println("\nvalues of interfaces") var zeroSlice []byte var zeroFunc func() // by embedding a 0-array func type in your struct, it is not comparable type doNotCompare [0]func() type notComparable struct { doNotCompare data *int32 } var zeroMap map[string]int var zeroChan chan int n := 42 for _, v := range []interface{}{ // basic types true, false, int(2000), int(-2000), uint(2000), int8(-3), int8(3), uint8(200), int16(-300), int16(300), uint16(50000), int32(7 << 20), int32(-7 << 20), uint32(7 << 20), int64(9 << 40), int64(-9 << 40), uint64(9 << 40), uintptr(12345), float32(3.14), float64(3.14), complex64(1.2 + 0.3i), complex128(1.3 + 0.4i), myint(32), "foo", unsafe.Pointer(new(int)), // channels zeroChan, mychan(zeroChan), // pointers new(int), new(error), &n, myptr(new(int)), // slices []byte{1, 2, 3}, make([]uint8, 2, 5), []rune{3, 5}, []string{"xyz", "Z"}, zeroSlice, []byte{}, []float32{1, 1.32}, []float64{1, 1.64}, []complex64{1, 1.64 + 0.3i}, []complex128{1, 1.128 + 0.4i}, myslice{5, 3, 11}, // array [3]int64{5, 8, 2}, [2]uint8{3, 5}, // functions zeroFunc, emptyFunc, // maps zeroMap, map[string]int{}, // structs struct{}{}, struct{ error }{}, struct { a uint8 b int16 c int8 }{42, 321, 123}, mystruct{5, point{-5, 3}, struct{}{}, []byte{'G', 'o'}, []byte{'X'}}, &linkedList{ foo: 42, }, struct{ A, B uintptr }{2, 3}, // interfaces []interface{}{3, "str", -4 + 2.5i}, } { showValue(reflect.ValueOf(v), "") } // Test reflect.New(). newInt8 := reflect.New(reflect.TypeOf(int8(0))) newInt8.Elem().SetInt(5) newInt16 := reflect.New(reflect.TypeOf(int16(0))) newInt16.Elem().SetInt(-800) newInt32 := reflect.New(reflect.TypeOf(int32(0))) newInt32.Elem().SetInt(1e8) newInt64 := reflect.New(reflect.TypeOf(int64(0))) newInt64.Elem().SetInt(-1e12) newComplex128 := reflect.New(reflect.TypeOf(0 + 0i)) newComplex128.Elem().SetComplex(-8 - 20e5i) for _, val := range []reflect.Value{newInt8, newInt16, newInt32, newInt64, newComplex128} { showValue(val, "") } // test sizes println("\nsizes:") for _, tc := range []struct { name string rt reflect.Type }{ {"int8", reflect.TypeOf(int8(0))}, {"int16", reflect.TypeOf(int16(0))}, {"int32", reflect.TypeOf(int32(0))}, {"int64", reflect.TypeOf(int64(0))}, {"uint8", reflect.TypeOf(uint8(0))}, {"uint16", reflect.TypeOf(uint16(0))}, {"uint32", reflect.TypeOf(uint32(0))}, {"uint64", reflect.TypeOf(uint64(0))}, {"float32", reflect.TypeOf(float32(0))}, {"float64", reflect.TypeOf(float64(0))}, {"complex64", reflect.TypeOf(complex64(0))}, {"complex128", reflect.TypeOf(complex128(0))}, } { println(tc.name, int(tc.rt.Size()), tc.rt.Bits()) } assertSize(reflect.TypeOf(uintptr(0)).Size() == unsafe.Sizeof(uintptr(0)), "uintptr") assertSize(reflect.TypeOf("").Size() == unsafe.Sizeof(""), "string") assertSize(reflect.TypeOf(new(int)).Size() == unsafe.Sizeof(new(int)), "*int") assertSize(reflect.TypeOf(zeroFunc).Size() == unsafe.Sizeof(zeroFunc), "func()") assertSize(reflect.TypeOf(zeroChan).Size() == unsafe.Sizeof(zeroChan), "chan int") assertSize(reflect.TypeOf(zeroMap).Size() == unsafe.Sizeof(zeroMap), "map[string]int") // make sure embedding a zero-sized "not comparable" struct does not add size to a struct assertSize(reflect.TypeOf(doNotCompare{}).Size() == unsafe.Sizeof(doNotCompare{}), "[0]func()") assertSize(unsafe.Sizeof(notComparable{}) == unsafe.Sizeof((*int32)(nil)), "struct{[0]func(); *int32}") // Test that offset is correctly calculated. // This doesn't just test reflect but also (indirectly) that unsafe.Alignof // works correctly. s := struct { small1 byte big1 int64 small2 byte big2 int64 }{} st := reflect.TypeOf(s) println("offset for int64 matches:", st.Field(1).Offset-st.Field(0).Offset == uintptr(unsafe.Pointer(&s.big1))-uintptr(unsafe.Pointer(&s.small1))) println("offset for complex128 matches:", st.Field(3).Offset-st.Field(2).Offset == uintptr(unsafe.Pointer(&s.big2))-uintptr(unsafe.Pointer(&s.small2))) // SetBool rv := reflect.ValueOf(new(bool)).Elem() rv.SetBool(true) if rv.Bool() != true { panic("could not set bool with SetBool()") } // SetInt for _, v := range []interface{}{ new(int), new(int8), new(int16), new(int32), new(int64), } { rv := reflect.ValueOf(v).Elem() rv.SetInt(99) if rv.Int() != 99 { panic("could not set integer with SetInt()") } } // SetUint for _, v := range []interface{}{ new(uint), new(uint8), new(uint16), new(uint32), new(uint64), new(uintptr), } { rv := reflect.ValueOf(v).Elem() rv.SetUint(99) if rv.Uint() != 99 { panic("could not set integer with SetUint()") } } // SetFloat for _, v := range []interface{}{ new(float32), new(float64), } { rv := reflect.ValueOf(v).Elem() rv.SetFloat(2.25) if rv.Float() != 2.25 { panic("could not set float with SetFloat()") } } // SetComplex for _, v := range []interface{}{ new(complex64), new(complex128), } { rv := reflect.ValueOf(v).Elem() rv.SetComplex(3 + 2i) if rv.Complex() != 3+2i { panic("could not set complex with SetComplex()") } } // SetString rv = reflect.ValueOf(new(string)).Elem() rv.SetString("foo") if rv.String() != "foo" { panic("could not set string with SetString()") } // Set int rv = reflect.ValueOf(new(int)).Elem() rv.SetInt(33) rv.Set(reflect.ValueOf(22)) if rv.Int() != 22 { panic("could not set int with Set()") } // Set uint8 rv = reflect.ValueOf(new(uint8)).Elem() rv.SetUint(33) rv.Set(reflect.ValueOf(uint8(22))) if rv.Uint() != 22 { panic("could not set uint8 with Set()") } // Set string rv = reflect.ValueOf(new(string)).Elem() rv.SetString("foo") rv.Set(reflect.ValueOf("bar")) if rv.String() != "bar" { panic("could not set string with Set()") } // Set complex128 rv = reflect.ValueOf(new(complex128)).Elem() rv.SetComplex(3 + 2i) rv.Set(reflect.ValueOf(4 + 8i)) if rv.Complex() != 4+8i { panic("could not set complex128 with Set()") } // Set to slice rv = reflect.ValueOf([]int{3, 5}) rv.Index(1).SetInt(7) if rv.Index(1).Int() != 7 { panic("could not set int in slice") } rv.Index(1).Set(reflect.ValueOf(8)) if rv.Index(1).Int() != 8 { panic("could not set int in slice") } if rv.Len() != 2 || rv.Index(0).Int() != 3 { panic("slice was changed while setting part of it") } testAppendSlice() // Test types that are created in reflect and never created elsewhere in a // value-to-interface conversion. v := reflect.ValueOf(new(unreferencedType)) switch v.Elem().Interface().(type) { case unreferencedType: println("type assertion succeeded for unreferenced type") default: println("type assertion failed (but should succeed)") } // Test type that is not referenced at all: not when creating the // reflect.Value (except through the field) and not with a type assert. // Previously this would result in a type assert failure because the Int() // method wasn't picked up. v = reflect.ValueOf(struct { X totallyUnreferencedType }{}) if v.Field(0).Interface().(interface { Int() int }).Int() != 42 { println("could not call method on totally unreferenced type") } if reflect.TypeOf(new(myint)) != reflect.PtrTo(reflect.TypeOf(myint(0))) { println("PtrTo failed for type myint") } if reflect.TypeOf(new(myslice)) != reflect.PtrTo(reflect.TypeOf(make(myslice, 0))) { println("PtrTo failed for type myslice") } if reflect.TypeOf(errorValue).Implements(errorType) != true { println("errorValue.Implements(errorType) was false, expected true") } if reflect.TypeOf(errorValue).Implements(stringerType) != false { println("errorValue.Implements(errorType) was true, expected false") } println("\nalignment / offset:") v2 := struct { noCompare [0]func() data byte }{} println("struct{[0]func(); byte}:", unsafe.Offsetof(v2.data) == uintptr(unsafe.Pointer(&v2.data))-uintptr(unsafe.Pointer(&v2))) println("\nstruct tags") TestStructTag() println("\nv.Interface() method") testInterfaceMethod() // Test reflect.DeepEqual. var selfref1, selfref2 selfref selfref1.x = &selfref1 selfref2.x = &selfref2 for i, tc := range []struct { v1, v2 interface{} equal bool }{ {int(5), int(5), true}, {int(3), int(5), false}, {int(5), uint(5), false}, {struct { a int b string }{3, "x"}, struct { a int b string }{3, "x"}, true}, {struct { a int b string }{3, "x"}, struct { a int b string }{3, "y"}, false}, {selfref1, selfref2, true}, } { result := reflect.DeepEqual(tc.v1, tc.v2) if result != tc.equal { if tc.equal { println("reflect.DeepEqual() test", i, "not equal while it should be") } else { println("reflect.DeepEqual() test", i, "equal while it should not be") } } } } func emptyFunc() { } func showValue(rv reflect.Value, indent string) { rt := rv.Type() if rt.Kind() != rv.Kind() { panic("type kind is different from value kind") } print(indent+"reflect type: ", rt.Kind().String()) if rv.CanSet() { print(" settable=true") } if rv.CanAddr() { print(" addrable=true") } if !rv.CanInterface() { print(" caninterface=false") } if !rt.Comparable() { print(" comparable=false") } println() switch rt.Kind() { case reflect.Bool: println(indent+" bool:", rv.Bool()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: println(indent+" int:", rv.Int()) case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: println(indent+" uint:", rv.Uint()) case reflect.Float32, reflect.Float64: println(indent+" float:", rv.Float()) case reflect.Complex64, reflect.Complex128: println(indent+" complex:", rv.Complex()) case reflect.String: println(indent+" string:", rv.String(), rv.Len()) for i := 0; i < rv.Len(); i++ { showValue(rv.Index(i), indent+" ") } case reflect.UnsafePointer: println(indent+" pointer:", rv.Pointer() != 0) case reflect.Array: println(indent+" array:", rt.Len(), rt.Elem().Kind().String(), int(rt.Size())) for i := 0; i < rv.Len(); i++ { showValue(rv.Index(i), indent+" ") } case reflect.Chan: println(indent+" chan:", rt.Elem().Kind().String()) println(indent+" nil:", rv.IsNil()) case reflect.Func: println(indent + " func") println(indent+" nil:", rv.IsNil()) case reflect.Interface: println(indent + " interface") println(indent+" nil:", rv.IsNil()) if !rv.IsNil() { showValue(rv.Elem(), indent+" ") } case reflect.Map: println(indent + " map") println(indent+" nil:", rv.IsNil()) case reflect.Ptr: println(indent+" pointer:", rv.Pointer() != 0, rt.Elem().Kind().String()) println(indent+" nil:", rv.IsNil()) if !rv.IsNil() { showValue(rv.Elem(), indent+" ") } case reflect.Slice: println(indent+" slice:", rt.Elem().Kind().String(), rv.Len(), rv.Cap()) println(indent+" pointer:", rv.Pointer() != 0) println(indent+" nil:", rv.IsNil()) for i := 0; i < rv.Len(); i++ { println(indent+" indexing:", i) showValue(rv.Index(i), indent+" ") } case reflect.Struct: println(indent+" struct:", rt.NumField()) for i := 0; i < rv.NumField(); i++ { field := rt.Field(i) println(indent+" field:", i, field.Name) println(indent+" pkg:", field.PkgPath) println(indent+" tag:", strconv.Quote(string(field.Tag))) println(indent+" embedded:", field.Anonymous) println(indent+" exported:", field.IsExported()) showValue(rv.Field(i), indent+" ") } default: println(indent + " unknown type kind!") } } func assertSize(ok bool, typ string) { if !ok { panic("size mismatch for type " + typ) } } // Test whether appending to a slice is equivalent between reflect and native // slice append. func testAppendSlice() { for i := 0; i < 100; i++ { dst := makeRandomSlice(i) src := makeRandomSlice(i) result1 := append(dst, src...) result2 := reflect.AppendSlice(reflect.ValueOf(dst), reflect.ValueOf(src)).Interface().([]uint32) if !sliceEqual(result1, result2) { println("slice: mismatch after runtime.SliceAppend with", len(dst), cap(dst), len(src), cap(src)) } } } func makeRandomSlice(max int) []uint32 { cap := randuint32() % uint32(max+1) len := randuint32() % (cap + 1) s := make([]uint32, len, cap) for i := uint32(0); i < len; i++ { s[i] = randuint32() } return s } func sliceEqual(s1, s2 []uint32) bool { if len(s1) != len(s2) { return false } for i, val := range s1 { if s2[i] != val { return false } } // Note: can't compare cap because the Go implementation has a different // behavior between the built-in append function and // reflect.AppendSlice. return true } type unreferencedType int type totallyUnreferencedType int func (totallyUnreferencedType) Int() int { return 42 } func TestStructTag() { type S struct { F string `species:"gopher" color:"blue"` } s := S{} st := reflect.TypeOf(s) field := st.Field(0) println(field.Tag.Get("color"), field.Tag.Get("species")) } // Test Interface() call: it should never return an interface itself. func testInterfaceMethod() { v := reflect.ValueOf(struct{ X interface{} }{X: 5}) println("kind:", v.Field(0).Kind().String()) itf := v.Field(0).Interface() switch n := itf.(type) { case int: println("int", n) // correct default: println("something else") // incorrect } } var xorshift32State uint32 = 1 func xorshift32(x uint32) uint32 { // Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" x ^= x << 13 x ^= x >> 17 x ^= x << 5 return x } func randuint32() uint32 { xorshift32State = xorshift32(xorshift32State) return xorshift32State }