为什么 map 类型的 kind 被报告为 53 而不是 21?

huangapple go评论87阅读模式
英文:

Why map type's kind is reported as 53 instead of 21?

问题

这是一个Go语言的代码片段,它定义了一些类型和常量。其中,p._type.typ.kind的值为53,表示map[int]int类型的kind值为53。但是在src/runtime/typekind.go中,kindMap的值为21,而不是53。同样地,kindChan的值为50,而不是18。这是因为在Go语言的运行时库中,类型的kind值可能与常量定义的值不完全一致,这取决于具体的实现和版本。因此,在不同的环境中,kind值可能会有所不同。

英文:

show code:

package main

import (
	"fmt"
	"unsafe"
)

// copy form src/runtime/type.go
type _type struct {
	size       uintptr
	ptrdata    uintptr // size of memory prefix holding all pointers
	hash       uint32
	tflag      tflag
	align      uint8
	fieldAlign uint8
	kind       uint8
	equal      func(unsafe.Pointer, unsafe.Pointer) bool
	gcdata     *byte
	str        nameOff
	ptrToThis  typeOff
}
type tflag uint8
type nameOff int32
type typeOff int32

// copy form src/runtime/runtime2.go
type eface struct {
	_type *maptype
	data  unsafe.Pointer
}

// copy form src/runtime/type.go
type maptype struct {
	typ    _type
	key    *_type
	elem   *_type
	bucket *_type // internal type representing a hash bucket
	// function for hashing keys (ptr to key, seed) -> hash
	hasher     func(unsafe.Pointer, uintptr) uintptr
	keysize    uint8  // size of key slot
	elemsize   uint8  // size of elem slot
	bucketsize uint16 // size of bucket
	flags      uint32
}

func main() {
	var t interface{} = map[int]int{1: 1}

	p := (*eface)(unsafe.Pointer(&t))

	fmt.Println(p._type.typ.kind) // 53
}

print 53,

but you can find in src/runtime/typekind.go

const (
	kindBool = 1 + iota
	kindInt
	kindInt8
	kindInt16
	kindInt32
	kindInt64
	kindUint
	kindUint8
	kindUint16
	kindUint32
	kindUint64
	kindUintptr
	kindFloat32
	kindFloat64
	kindComplex64
	kindComplex128
	kindArray
	kindChan
	kindFunc
	kindInterface
	kindMap // 21
	kindPtr
	kindSlice
	kindString
	kindStruct
	kindUnsafePointer

	kindDirectIface = 1 << 5
	kindGCProg      = 1 << 6
	kindMask        = (1 << 5) - 1
)

the map type is const 21. Similarly, chan is 50 instead of kindChan(18). Why?

答案1

得分: 2

如果你查看src/runtime/typekind.go,你会发现有一个函数用于检查值是否直接存储在接口值中,这适用于你的情况,因为你创建了一个类型为interface{}的变量t,但将一个映射类型存储到其中。

// isDirectIface报告t是否直接存储在接口值中。
func isDirectIface(t *_type) bool {
	return t.kind&kindDirectIface != 0
}

当你将其应用于p的值,即isDirectIface(&p._type.typ),它返回true,因为与接口类型对应的底层位值被设置为1 (kindDirectIface = 1 << 5,32)。

因此,实际上,值53表示(十进制21+32),一个映射类型21(kindMap)存储为一个接口类型32(kindDirectIface)。

英文:

If you look at the src/runtime/typekind.go, there is a function to check if the value is stored directly in an interface value, which applies to your case, as you are creating t of interface{} but storing a map type to it.

// isDirectIface reports whether t is stored directly in an interface value.
func isDirectIface(t *_type) bool {
	return t.kind&amp;kindDirectIface != 0
}

When using that on your value of p as isDirectIface(&amp;p._type.typ) it returns true, because of the underlying bit value corresponding to interface type is set (kindDirectIface = 1 &lt;&lt; 5, 32)

So in effect, the value 53 represents (decimal 21+32) a map type 21 (kindMap) stored as an interface type 32 (kindDirectIface)

huangapple
  • 本文由 发表于 2022年1月10日 11:59:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/70647654.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定