reflect: add limited support for all type kinds
This commit makes sure all Go types can be encoded in the interface type code, so that Type.Kind() always returns a proper type kind for any non-nil interface.
Этот коммит содержится в:
родитель
101f2e519b
коммит
dfef168139
6 изменённых файлов: 377 добавлений и 66 удалений
|
@ -8,6 +8,8 @@ package compiler
|
||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/ir"
|
"github.com/tinygo-org/tinygo/ir"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
|
@ -92,55 +94,91 @@ func (c *Compiler) getTypeCode(typ types.Type) llvm.Value {
|
||||||
// interface lowering pass to assign type codes as expected by the reflect
|
// interface lowering pass to assign type codes as expected by the reflect
|
||||||
// package. See getTypeCodeNum.
|
// package. See getTypeCodeNum.
|
||||||
func getTypeCodeName(t types.Type) string {
|
func getTypeCodeName(t types.Type) string {
|
||||||
|
name := ""
|
||||||
|
if named, ok := t.(*types.Named); ok {
|
||||||
|
name = "~" + named.String() + ":"
|
||||||
|
t = t.Underlying()
|
||||||
|
}
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
|
case *types.Array:
|
||||||
|
return "array:" + name + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
|
||||||
case *types.Basic:
|
case *types.Basic:
|
||||||
var name string
|
var kind string
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case types.Bool:
|
case types.Bool:
|
||||||
name = "bool"
|
kind = "bool"
|
||||||
case types.Int:
|
case types.Int:
|
||||||
name = "int"
|
kind = "int"
|
||||||
case types.Int8:
|
case types.Int8:
|
||||||
name = "int8"
|
kind = "int8"
|
||||||
case types.Int16:
|
case types.Int16:
|
||||||
name = "int16"
|
kind = "int16"
|
||||||
case types.Int32:
|
case types.Int32:
|
||||||
name = "int32"
|
kind = "int32"
|
||||||
case types.Int64:
|
case types.Int64:
|
||||||
name = "int64"
|
kind = "int64"
|
||||||
case types.Uint:
|
case types.Uint:
|
||||||
name = "uint"
|
kind = "uint"
|
||||||
case types.Uint8:
|
case types.Uint8:
|
||||||
name = "uint8"
|
kind = "uint8"
|
||||||
case types.Uint16:
|
case types.Uint16:
|
||||||
name = "uint16"
|
kind = "uint16"
|
||||||
case types.Uint32:
|
case types.Uint32:
|
||||||
name = "uint32"
|
kind = "uint32"
|
||||||
case types.Uint64:
|
case types.Uint64:
|
||||||
name = "uint64"
|
kind = "uint64"
|
||||||
case types.Uintptr:
|
case types.Uintptr:
|
||||||
name = "uintptr"
|
kind = "uintptr"
|
||||||
case types.Float32:
|
case types.Float32:
|
||||||
name = "float32"
|
kind = "float32"
|
||||||
case types.Float64:
|
case types.Float64:
|
||||||
name = "float64"
|
kind = "float64"
|
||||||
case types.Complex64:
|
case types.Complex64:
|
||||||
name = "complex64"
|
kind = "complex64"
|
||||||
case types.Complex128:
|
case types.Complex128:
|
||||||
name = "complex128"
|
kind = "complex128"
|
||||||
case types.String:
|
case types.String:
|
||||||
name = "string"
|
kind = "string"
|
||||||
case types.UnsafePointer:
|
case types.UnsafePointer:
|
||||||
name = "unsafeptr"
|
kind = "unsafeptr"
|
||||||
default:
|
default:
|
||||||
panic("unknown basic type: " + t.Name())
|
panic("unknown basic type: " + t.Name())
|
||||||
}
|
}
|
||||||
return "basic:" + name
|
return "basic:" + name + kind
|
||||||
|
case *types.Chan:
|
||||||
|
return "chan:" + name + getTypeCodeName(t.Elem())
|
||||||
|
case *types.Interface:
|
||||||
|
methods := make([]string, t.NumMethods())
|
||||||
|
for i := 0; i < t.NumMethods(); i++ {
|
||||||
|
methods[i] = getTypeCodeName(t.Method(i).Type())
|
||||||
|
}
|
||||||
|
return "interface:" + name + "{" + strings.Join(methods, ",") + "}"
|
||||||
|
case *types.Map:
|
||||||
|
keyType := getTypeCodeName(t.Key())
|
||||||
|
elemType := getTypeCodeName(t.Elem())
|
||||||
|
return "map:" + name + "{" + keyType + "," + elemType + "}"
|
||||||
|
case *types.Pointer:
|
||||||
|
return "pointer:" + name + getTypeCodeName(t.Elem())
|
||||||
|
case *types.Signature:
|
||||||
|
params := make([]string, t.Params().Len())
|
||||||
|
for i := 0; i < t.Params().Len(); i++ {
|
||||||
|
params[i] = getTypeCodeName(t.Params().At(i).Type())
|
||||||
|
}
|
||||||
|
results := make([]string, t.Results().Len())
|
||||||
|
for i := 0; i < t.Results().Len(); i++ {
|
||||||
|
results[i] = getTypeCodeName(t.Results().At(i).Type())
|
||||||
|
}
|
||||||
|
return "func:" + name + "{" + strings.Join(params, ",") + "}{" + strings.Join(results, ",") + "}"
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
return "slice:" + getTypeCodeName(t.Elem())
|
return "slice:" + name + getTypeCodeName(t.Elem())
|
||||||
|
case *types.Struct:
|
||||||
|
elems := make([]string, t.NumFields())
|
||||||
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
|
elems[i] = getTypeCodeName(t.Field(i).Type())
|
||||||
|
}
|
||||||
|
return "struct:" + name + "{" + strings.Join(elems, ",") + "}"
|
||||||
default:
|
default:
|
||||||
// Unknown type, fall back to the .String() method for identification.
|
panic("unknown type: " + t.String())
|
||||||
return "other:" + t.String()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,18 +39,12 @@ func (c *Compiler) assignTypeCodes(typeSlice typeInfoSlice) {
|
||||||
|
|
||||||
// Assign typecodes the way the reflect package expects.
|
// Assign typecodes the way the reflect package expects.
|
||||||
fallbackIndex := 1
|
fallbackIndex := 1
|
||||||
|
namedTypes := make(map[string]int)
|
||||||
for _, t := range typeSlice {
|
for _, t := range typeSlice {
|
||||||
if t.name[:5] != "type:" {
|
if t.name[:5] != "type:" {
|
||||||
panic("expected type name to start with 'type:'")
|
panic("expected type name to start with 'type:'")
|
||||||
}
|
}
|
||||||
num := c.getTypeCodeNum(t.name[5:])
|
num := c.getTypeCodeNum(t.name[5:], &fallbackIndex, namedTypes)
|
||||||
if num == nil {
|
|
||||||
// Fallback/unsupported types have a typecode with the lowest bits
|
|
||||||
// set to 11.
|
|
||||||
t.num = uint64(fallbackIndex<<2 | 3)
|
|
||||||
fallbackIndex++
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if num.BitLen() > c.uintptrType.IntTypeWidth() || !num.IsUint64() {
|
if num.BitLen() > c.uintptrType.IntTypeWidth() || !num.IsUint64() {
|
||||||
// TODO: support this in some way, using a side table for example.
|
// TODO: support this in some way, using a side table for example.
|
||||||
// That's less efficient but better than not working at all.
|
// That's less efficient but better than not working at all.
|
||||||
|
@ -65,20 +59,98 @@ func (c *Compiler) assignTypeCodes(typeSlice typeInfoSlice) {
|
||||||
// getTypeCodeNum returns the typecode for a given type as expected by the
|
// getTypeCodeNum returns the typecode for a given type as expected by the
|
||||||
// reflect package. Also see getTypeCodeName, which serializes types to a string
|
// reflect package. Also see getTypeCodeName, which serializes types to a string
|
||||||
// based on a types.Type value for this function.
|
// based on a types.Type value for this function.
|
||||||
func (c *Compiler) getTypeCodeNum(name string) *big.Int {
|
func (c *Compiler) getTypeCodeNum(id string, fallbackIndex *int, namedTypes map[string]int) *big.Int {
|
||||||
if strings.HasPrefix(name, "basic:") {
|
// Note: see src/reflect/type.go for bit allocations.
|
||||||
// Basic types have a typecode with the lowest bits set to 00.
|
// A type can be named or unnamed. Example of both:
|
||||||
num, ok := basicTypes[name[len("basic:"):]]
|
// basic:~foo:uint64
|
||||||
|
// basic:uint64
|
||||||
|
// Extract the class (basic, slice, pointer, etc.), the name, and the
|
||||||
|
// contents of this type ID string. Allocate bits based on that, as
|
||||||
|
// src/runtime/types.go expects.
|
||||||
|
class := id[:strings.IndexByte(id, ':')]
|
||||||
|
value := id[len(class)+1:]
|
||||||
|
name := ""
|
||||||
|
if value[0] == '~' {
|
||||||
|
name = value[1:strings.IndexByte(value, ':')]
|
||||||
|
value = value[len(name)+2:]
|
||||||
|
}
|
||||||
|
if class == "basic" {
|
||||||
|
// Basic types follow the following bit pattern:
|
||||||
|
// ...xxxxx0
|
||||||
|
// where xxxxx is allocated for the 18 possible basic types and all the
|
||||||
|
// upper bits are used to indicate the named type.
|
||||||
|
num, ok := basicTypes[value]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("invalid basic type: " + name)
|
panic("invalid basic type: " + id)
|
||||||
}
|
}
|
||||||
return big.NewInt(num<<2 | 0)
|
if name != "" {
|
||||||
} else if strings.HasPrefix(name, "slice:") {
|
// This type is named, set the upper bits to the name ID.
|
||||||
// Slices have a typecode with the lowest bits set to 01.
|
num |= int64(getNamedTypeNum(namedTypes, name)) << 5
|
||||||
num := c.getTypeCodeNum(name[len("slice:"):])
|
}
|
||||||
num.Lsh(num, 2).Or(num, big.NewInt(1))
|
return big.NewInt(num << 1)
|
||||||
return num
|
|
||||||
} else {
|
} else {
|
||||||
return nil
|
// Complex types use the following bit pattern:
|
||||||
|
// ...nxxx1
|
||||||
|
// where xxx indicates the complex type (any non-basic type). The upper
|
||||||
|
// bits contain whatever the type contains. Types that wrap a single
|
||||||
|
// other type (channel, interface, pointer, slice) just contain the bits
|
||||||
|
// of the wrapped type. Other types (like struct) have a different
|
||||||
|
// method of encoding the contents of the type.
|
||||||
|
var num *big.Int
|
||||||
|
var classNumber int64
|
||||||
|
switch class {
|
||||||
|
case "chan":
|
||||||
|
num = c.getTypeCodeNum(value, fallbackIndex, namedTypes)
|
||||||
|
classNumber = 0
|
||||||
|
case "interface":
|
||||||
|
num = big.NewInt(int64(*fallbackIndex))
|
||||||
|
*fallbackIndex++
|
||||||
|
classNumber = 1
|
||||||
|
case "pointer":
|
||||||
|
num = c.getTypeCodeNum(value, fallbackIndex, namedTypes)
|
||||||
|
classNumber = 2
|
||||||
|
case "slice":
|
||||||
|
num = c.getTypeCodeNum(value, fallbackIndex, namedTypes)
|
||||||
|
classNumber = 3
|
||||||
|
case "array":
|
||||||
|
num = big.NewInt(int64(*fallbackIndex))
|
||||||
|
*fallbackIndex++
|
||||||
|
classNumber = 4
|
||||||
|
case "func":
|
||||||
|
num = big.NewInt(int64(*fallbackIndex))
|
||||||
|
*fallbackIndex++
|
||||||
|
classNumber = 5
|
||||||
|
case "map":
|
||||||
|
num = big.NewInt(int64(*fallbackIndex))
|
||||||
|
*fallbackIndex++
|
||||||
|
classNumber = 6
|
||||||
|
case "struct":
|
||||||
|
num = big.NewInt(int64(*fallbackIndex))
|
||||||
|
*fallbackIndex++
|
||||||
|
classNumber = 7
|
||||||
|
default:
|
||||||
|
panic("unknown type kind: " + id)
|
||||||
|
}
|
||||||
|
if name == "" {
|
||||||
|
num.Lsh(num, 5).Or(num, big.NewInt((classNumber<<1)+1))
|
||||||
|
} else {
|
||||||
|
// TODO: store num in a sidetable
|
||||||
|
num = big.NewInt(int64(getNamedTypeNum(namedTypes, name))<<1 | 1)
|
||||||
|
num.Lsh(num, 4).Or(num, big.NewInt((classNumber<<1)+1))
|
||||||
|
}
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getNamedTypeNum returns an appropriate (unique) number for the given named
|
||||||
|
// type. If the name already has a number that number is returned, else a new
|
||||||
|
// number is returned. The number is always non-zero.
|
||||||
|
func getNamedTypeNum(namedTypes map[string]int, name string) int {
|
||||||
|
if num, ok := namedTypes[name]; ok {
|
||||||
|
return num
|
||||||
|
} else {
|
||||||
|
num = len(namedTypes) + 1
|
||||||
|
namedTypes[name] = num
|
||||||
|
return num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,26 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Kind is the number that the compiler uses for this type.
|
// The compiler uses a compact encoding to store type information. Unlike the
|
||||||
|
// main Go compiler, most of the types are stored directly in the type code.
|
||||||
//
|
//
|
||||||
// Not used directly. These types are all replaced with the number the compiler
|
// Type code bit allocation:
|
||||||
// uses internally for the type.
|
// xxxxx0: basic types, where xxxxx is the basic type number (never 0).
|
||||||
|
// The higher bits indicate the named type, if any.
|
||||||
|
// nxxx1: complex types, where n indicates whether this is a named type (named
|
||||||
|
// if set) and xxx contains the type kind number:
|
||||||
|
// 0 (0001): Chan
|
||||||
|
// 1 (0011): Interface
|
||||||
|
// 2 (0101): Ptr
|
||||||
|
// 3 (0111): Slice
|
||||||
|
// 4 (1001): Array
|
||||||
|
// 5 (1011): Func
|
||||||
|
// 6 (1101): Map
|
||||||
|
// 7 (1111): Struct
|
||||||
|
// The higher bits are either the contents of the type depending on the
|
||||||
|
// type (if n is clear) or indicate the number of the named type (if n
|
||||||
|
// is set).
|
||||||
|
|
||||||
type Kind uintptr
|
type Kind uintptr
|
||||||
|
|
||||||
// Copied from reflect/type.go
|
// Copied from reflect/type.go
|
||||||
|
@ -32,13 +48,13 @@ const (
|
||||||
Complex128
|
Complex128
|
||||||
String
|
String
|
||||||
UnsafePointer
|
UnsafePointer
|
||||||
Array
|
|
||||||
Chan
|
Chan
|
||||||
Func
|
|
||||||
Interface
|
Interface
|
||||||
Map
|
|
||||||
Ptr
|
Ptr
|
||||||
Slice
|
Slice
|
||||||
|
Array
|
||||||
|
Func
|
||||||
|
Map
|
||||||
Struct
|
Struct
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,8 +96,22 @@ func (k Kind) String() string {
|
||||||
return "string"
|
return "string"
|
||||||
case UnsafePointer:
|
case UnsafePointer:
|
||||||
return "unsafe.Pointer"
|
return "unsafe.Pointer"
|
||||||
|
case Chan:
|
||||||
|
return "chan"
|
||||||
|
case Interface:
|
||||||
|
return "interface"
|
||||||
|
case Ptr:
|
||||||
|
return "ptr"
|
||||||
case Slice:
|
case Slice:
|
||||||
return "slice"
|
return "slice"
|
||||||
|
case Array:
|
||||||
|
return "array"
|
||||||
|
case Func:
|
||||||
|
return "func"
|
||||||
|
case Map:
|
||||||
|
return "map"
|
||||||
|
case Struct:
|
||||||
|
return "struct"
|
||||||
default:
|
default:
|
||||||
return "invalid"
|
return "invalid"
|
||||||
}
|
}
|
||||||
|
@ -89,7 +119,7 @@ func (k Kind) String() string {
|
||||||
|
|
||||||
// basicType returns a new Type for this kind if Kind is a basic type.
|
// basicType returns a new Type for this kind if Kind is a basic type.
|
||||||
func (k Kind) basicType() Type {
|
func (k Kind) basicType() Type {
|
||||||
return Type(k << 2 | 0)
|
return Type(k << 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The typecode as used in an interface{}.
|
// The typecode as used in an interface{}.
|
||||||
|
@ -104,22 +134,22 @@ func (t Type) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Type) Kind() Kind {
|
func (t Type) Kind() Kind {
|
||||||
if t % 4 == 0 {
|
if t % 2 == 0 {
|
||||||
// Basic type
|
// basic type
|
||||||
return Kind(t >> 2)
|
return Kind((t >> 1) % 32)
|
||||||
} else if t % 4 == 1 {
|
|
||||||
// Slice
|
|
||||||
return Slice
|
|
||||||
} else {
|
} else {
|
||||||
return Invalid // TODO
|
return Kind(t >> 1) % 8 + 19
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Type) Elem() Type {
|
func (t Type) Elem() Type {
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
case Slice:
|
case Chan, Ptr, Slice:
|
||||||
return t >> 2
|
if (t >> 4) % 2 != 0 {
|
||||||
default: // not implemented: Array, Chan, Map, Ptr
|
panic("unimplemented: (reflect.Type).Elem() for named types")
|
||||||
|
}
|
||||||
|
return t >> 5
|
||||||
|
default: // not implemented: Array, Map
|
||||||
panic("unimplemented: (reflect.Type).Elem()")
|
panic("unimplemented: (reflect.Type).Elem()")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +194,7 @@ func (t Type) Size() uintptr {
|
||||||
return 16
|
return 16
|
||||||
case String:
|
case String:
|
||||||
return unsafe.Sizeof(StringHeader{})
|
return unsafe.Sizeof(StringHeader{})
|
||||||
case UnsafePointer:
|
case UnsafePointer, Chan, Map, Ptr:
|
||||||
return unsafe.Sizeof(uintptr(0))
|
return unsafe.Sizeof(uintptr(0))
|
||||||
case Slice:
|
case Slice:
|
||||||
return unsafe.Sizeof(SliceHeader{})
|
return unsafe.Sizeof(SliceHeader{})
|
||||||
|
|
|
@ -31,16 +31,38 @@ func (v Value) Kind() Kind {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Value) IsNil() bool {
|
func (v Value) IsNil() bool {
|
||||||
panic("unimplemented: (reflect.Value).IsNil()")
|
switch v.Kind() {
|
||||||
|
case Chan, Map, Ptr:
|
||||||
|
return v.value == nil
|
||||||
|
case Func:
|
||||||
|
if v.value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
fn := (*funcHeader)(v.value)
|
||||||
|
return fn.Code == nil
|
||||||
|
case Slice:
|
||||||
|
if v.value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
slice := (*SliceHeader)(v.value)
|
||||||
|
return slice.Data == 0
|
||||||
|
case Interface:
|
||||||
|
panic("unimplemented: (reflect.Value).IsNil()")
|
||||||
|
default:
|
||||||
|
panic(&ValueError{"IsNil"})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v Value) Pointer() uintptr {
|
func (v Value) Pointer() uintptr {
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
case UnsafePointer:
|
case Chan, Map, Ptr, UnsafePointer:
|
||||||
return uintptr(v.value)
|
return uintptr(v.value)
|
||||||
case Chan, Func, Map, Ptr, Slice:
|
case Slice:
|
||||||
|
slice := (*SliceHeader)(v.value)
|
||||||
|
return slice.Data
|
||||||
|
case Func:
|
||||||
panic("unimplemented: (reflect.Value).Pointer()")
|
panic("unimplemented: (reflect.Value).Pointer()")
|
||||||
default:
|
default: // not implemented: Func
|
||||||
panic(&ValueError{"Pointer"})
|
panic(&ValueError{"Pointer"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,6 +344,11 @@ func MakeSlice(typ Type, len, cap int) Value {
|
||||||
panic("unimplemented: reflect.MakeSlice()")
|
panic("unimplemented: reflect.MakeSlice()")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type funcHeader struct {
|
||||||
|
Context unsafe.Pointer
|
||||||
|
Code unsafe.Pointer
|
||||||
|
}
|
||||||
|
|
||||||
type SliceHeader struct {
|
type SliceHeader struct {
|
||||||
Data uintptr
|
Data uintptr
|
||||||
Len uintptr
|
Len uintptr
|
||||||
|
|
81
testdata/reflect.go
предоставленный
81
testdata/reflect.go
предоставленный
|
@ -5,16 +5,29 @@ import (
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type myint int
|
type (
|
||||||
|
myint int
|
||||||
|
myslice []byte
|
||||||
|
myslice2 []myint
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("matching types")
|
println("matching types")
|
||||||
println(reflect.TypeOf(int(3)) == reflect.TypeOf(int(5)))
|
println(reflect.TypeOf(int(3)) == reflect.TypeOf(int(5)))
|
||||||
println(reflect.TypeOf(int(3)) == reflect.TypeOf(uint(5)))
|
println(reflect.TypeOf(int(3)) == reflect.TypeOf(uint(5)))
|
||||||
println(reflect.TypeOf(myint(3)) == reflect.TypeOf(int(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")
|
println("\nvalues of interfaces")
|
||||||
|
var zeroSlice []byte
|
||||||
|
var zeroFunc func()
|
||||||
|
var zeroMap map[string]int
|
||||||
|
var zeroChan chan int
|
||||||
|
n := 42
|
||||||
for _, v := range []interface{}{
|
for _, v := range []interface{}{
|
||||||
|
// basic types
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
int(2000),
|
int(2000),
|
||||||
|
@ -37,15 +50,57 @@ func main() {
|
||||||
float64(3.14),
|
float64(3.14),
|
||||||
complex64(1.2 + 0.3i),
|
complex64(1.2 + 0.3i),
|
||||||
complex128(1.3 + 0.4i),
|
complex128(1.3 + 0.4i),
|
||||||
|
myint(32),
|
||||||
"foo",
|
"foo",
|
||||||
unsafe.Pointer(new(int)),
|
unsafe.Pointer(new(int)),
|
||||||
|
// channels
|
||||||
|
zeroChan,
|
||||||
|
// pointers
|
||||||
|
new(int),
|
||||||
|
new(error),
|
||||||
|
&n,
|
||||||
|
// slices
|
||||||
[]byte{1, 2, 3},
|
[]byte{1, 2, 3},
|
||||||
make([]uint8, 2, 5),
|
make([]uint8, 2, 5),
|
||||||
[]rune{3, 5},
|
[]rune{3, 5},
|
||||||
[]string{"xyz", "Z"},
|
[]string{"xyz", "Z"},
|
||||||
|
zeroSlice,
|
||||||
|
[]byte{},
|
||||||
|
// array
|
||||||
|
[4]int{1, 2, 3, 4},
|
||||||
|
// functions
|
||||||
|
zeroFunc,
|
||||||
|
emptyFunc,
|
||||||
|
// maps
|
||||||
|
zeroMap,
|
||||||
|
map[string]int{},
|
||||||
|
// structs
|
||||||
|
struct{}{},
|
||||||
|
struct{ error }{},
|
||||||
} {
|
} {
|
||||||
showValue(v, "")
|
showValue(v, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test sizes
|
||||||
|
println("\nsizes:")
|
||||||
|
println("int8", int(reflect.TypeOf(int8(0)).Size()))
|
||||||
|
println("int16", int(reflect.TypeOf(int16(0)).Size()))
|
||||||
|
println("int32", int(reflect.TypeOf(int32(0)).Size()))
|
||||||
|
println("int64", int(reflect.TypeOf(int64(0)).Size()))
|
||||||
|
println("uint8", int(reflect.TypeOf(uint8(0)).Size()))
|
||||||
|
println("uint16", int(reflect.TypeOf(uint16(0)).Size()))
|
||||||
|
println("uint32", int(reflect.TypeOf(uint32(0)).Size()))
|
||||||
|
println("uint64", int(reflect.TypeOf(uint64(0)).Size()))
|
||||||
|
println("float32", int(reflect.TypeOf(float32(0)).Size()))
|
||||||
|
println("float64", int(reflect.TypeOf(float64(0)).Size()))
|
||||||
|
println("complex64", int(reflect.TypeOf(complex64(0)).Size()))
|
||||||
|
println("complex128", int(reflect.TypeOf(complex128(0)).Size()))
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
func emptyFunc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func showValue(v interface{}, indent string) {
|
func showValue(v interface{}, indent string) {
|
||||||
|
@ -79,13 +134,37 @@ func showValue(v interface{}, indent string) {
|
||||||
}
|
}
|
||||||
case reflect.UnsafePointer:
|
case reflect.UnsafePointer:
|
||||||
println(indent+" pointer:", rv.Pointer() != 0)
|
println(indent+" pointer:", rv.Pointer() != 0)
|
||||||
|
case reflect.Array:
|
||||||
|
println(indent + " array")
|
||||||
|
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.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())
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
println(indent+" slice:", rt.Elem().Kind().String(), rv.Len(), rv.Cap())
|
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++ {
|
for i := 0; i < rv.Len(); i++ {
|
||||||
println(indent+" indexing:", i)
|
println(indent+" indexing:", i)
|
||||||
showValue(rv.Index(i).Interface(), indent+" ")
|
showValue(rv.Index(i).Interface(), indent+" ")
|
||||||
}
|
}
|
||||||
|
case reflect.Struct:
|
||||||
|
println(indent + " struct")
|
||||||
default:
|
default:
|
||||||
println(indent + " unknown type kind!")
|
println(indent + " unknown type kind!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func assertSize(ok bool, typ string) {
|
||||||
|
if !ok {
|
||||||
|
panic("size mismatch for type " + typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
65
testdata/reflect.txt
предоставленный
65
testdata/reflect.txt
предоставленный
|
@ -2,6 +2,9 @@ matching types
|
||||||
true
|
true
|
||||||
false
|
false
|
||||||
false
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
false
|
||||||
|
|
||||||
values of interfaces
|
values of interfaces
|
||||||
reflect type: bool
|
reflect type: bool
|
||||||
|
@ -48,6 +51,8 @@ reflect type: complex64
|
||||||
complex: (+1.200000e+000+3.000000e-001i)
|
complex: (+1.200000e+000+3.000000e-001i)
|
||||||
reflect type: complex128
|
reflect type: complex128
|
||||||
complex: (+1.300000e+000+4.000000e-001i)
|
complex: (+1.300000e+000+4.000000e-001i)
|
||||||
|
reflect type: int
|
||||||
|
int: 32
|
||||||
reflect type: string
|
reflect type: string
|
||||||
string: foo 3
|
string: foo 3
|
||||||
reflect type: uint8
|
reflect type: uint8
|
||||||
|
@ -58,8 +63,22 @@ reflect type: string
|
||||||
uint: 111
|
uint: 111
|
||||||
reflect type: unsafe.Pointer
|
reflect type: unsafe.Pointer
|
||||||
pointer: true
|
pointer: true
|
||||||
|
reflect type: chan
|
||||||
|
chan: int
|
||||||
|
nil: true
|
||||||
|
reflect type: ptr
|
||||||
|
pointer: true int
|
||||||
|
nil: false
|
||||||
|
reflect type: ptr
|
||||||
|
pointer: true interface
|
||||||
|
nil: false
|
||||||
|
reflect type: ptr
|
||||||
|
pointer: true int
|
||||||
|
nil: false
|
||||||
reflect type: slice
|
reflect type: slice
|
||||||
slice: uint8 3 3
|
slice: uint8 3 3
|
||||||
|
pointer: true
|
||||||
|
nil: false
|
||||||
indexing: 0
|
indexing: 0
|
||||||
reflect type: uint8
|
reflect type: uint8
|
||||||
uint: 1
|
uint: 1
|
||||||
|
@ -71,6 +90,8 @@ reflect type: slice
|
||||||
uint: 3
|
uint: 3
|
||||||
reflect type: slice
|
reflect type: slice
|
||||||
slice: uint8 2 5
|
slice: uint8 2 5
|
||||||
|
pointer: true
|
||||||
|
nil: false
|
||||||
indexing: 0
|
indexing: 0
|
||||||
reflect type: uint8
|
reflect type: uint8
|
||||||
uint: 0
|
uint: 0
|
||||||
|
@ -79,6 +100,8 @@ reflect type: slice
|
||||||
uint: 0
|
uint: 0
|
||||||
reflect type: slice
|
reflect type: slice
|
||||||
slice: int32 2 2
|
slice: int32 2 2
|
||||||
|
pointer: true
|
||||||
|
nil: false
|
||||||
indexing: 0
|
indexing: 0
|
||||||
reflect type: int32
|
reflect type: int32
|
||||||
int: 3
|
int: 3
|
||||||
|
@ -87,6 +110,8 @@ reflect type: slice
|
||||||
int: 5
|
int: 5
|
||||||
reflect type: slice
|
reflect type: slice
|
||||||
slice: string 2 2
|
slice: string 2 2
|
||||||
|
pointer: true
|
||||||
|
nil: false
|
||||||
indexing: 0
|
indexing: 0
|
||||||
reflect type: string
|
reflect type: string
|
||||||
string: xyz 3
|
string: xyz 3
|
||||||
|
@ -101,3 +126,43 @@ reflect type: slice
|
||||||
string: Z 1
|
string: Z 1
|
||||||
reflect type: uint8
|
reflect type: uint8
|
||||||
uint: 90
|
uint: 90
|
||||||
|
reflect type: slice
|
||||||
|
slice: uint8 0 0
|
||||||
|
pointer: false
|
||||||
|
nil: true
|
||||||
|
reflect type: slice
|
||||||
|
slice: uint8 0 0
|
||||||
|
pointer: true
|
||||||
|
nil: false
|
||||||
|
reflect type: array
|
||||||
|
array
|
||||||
|
reflect type: func
|
||||||
|
func
|
||||||
|
nil: true
|
||||||
|
reflect type: func
|
||||||
|
func
|
||||||
|
nil: false
|
||||||
|
reflect type: map
|
||||||
|
map
|
||||||
|
nil: true
|
||||||
|
reflect type: map
|
||||||
|
map
|
||||||
|
nil: false
|
||||||
|
reflect type: struct
|
||||||
|
struct
|
||||||
|
reflect type: struct
|
||||||
|
struct
|
||||||
|
|
||||||
|
sizes:
|
||||||
|
int8 1
|
||||||
|
int16 2
|
||||||
|
int32 4
|
||||||
|
int64 8
|
||||||
|
uint8 1
|
||||||
|
uint16 2
|
||||||
|
uint32 4
|
||||||
|
uint64 8
|
||||||
|
float32 4
|
||||||
|
float64 8
|
||||||
|
complex64 8
|
||||||
|
complex128 16
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче