You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

577 lines
14 KiB

package main
import (
"errors"
"reflect"
"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
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,
},
// 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()")
// 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 !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+" tag:", 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
}