golang 对象(struct) hash原理

map里面的key的hash是怎么实现的

源码:src/runtime/map.go
golang的map是内置关键字,不管是get还是set都需要通过key的hash找到对应的存储实体。具体的hash过程如下代码:

type maptype struct {
   
	typ        _type
	key        *_type
	elem       *_type
	bucket     *_type // internal type representing a hash bucket
	keysize    uint8  // size of key slot
	elemsize   uint8  // size of elem slot
	bucketsize uint16 // size of bucket
	flags      uint32
}

//t *maptype
alg := t.key.alg
hash := alg.hash(key, uintptr(h.hash0))

这里其实就是拿到key对应的类型,然后获取当前key的类型的hash算法。然后调用hash函数。

hash函数的定义在这里:

// typeAlg is also copied/used in reflect/type.go.
// keep them in sync.
type typeAlg struct {
   
	// function for hashing objects of this type
	// (ptr to object, seed) -> hash
	hash func(unsafe.Pointer, uintptr) uintptr
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	equal func(unsafe.Pointer, unsafe.Pointer) bool
}

可以知道,入参是指向key的指针,第二个参数是hash种子。

golang里面的对象的hash原理

golang里面每种数据类型的hash是与数据类型强相关的,并且是由编译器负责做类型绑定的。在src/runtime/alg.go 里面定义个一个map[type]typeAlg,用于表示每个数据类型对应的 typeAlg。

var algarray = [alg_max]typeAlg{
   
	alg_NOEQ:     {
   nil, nil},
	alg_MEM0:     {
   memhash0, memequal0},
	alg_MEM8:     {
   memhash8, memequal8},
	alg_MEM16:    {
   memhash16, memequal16},
	alg_MEM32:    {
   memhash32, memequal32},
	alg_MEM64:    {
   memhash64, memequal64},
	alg_MEM128:   {
   memhash128, memequal128},
	alg_STRING:   {
   strhash, strequal},
	alg_INTER:    {
   interhash, interequal},
	alg_NILINTER: {
   nilinterhash, nilinterequal},
	alg_FLOAT32:  {
   f32hash, f32equal},
	alg_FLOAT64:  {
   f64hash, f64equal},
	alg_CPLX64:   {
   c64hash, c64equal},
	alg_CPLX128:  {
   c128hash, c128equal},
}

上面的hash函数,最后实际上底层都会调用:func memhash(p unsafe.Pointer, seed, s uintptr) uintptr 函数。以strhash函数为例:

func strhash(a unsafe.Pointer, h uintptr) uintptr {
   
	x := (*stringStruct)(a)
	return memhash(x.str, h, uintptr(x.len))
}

下面看一下memhash函数, src/runtime/hash64.go

// p表示需要hash的对象的地址
// seed 是hash 种子,
// s是需要hash的对象的字节数
func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
   
	if (GOARCH == "amd64" || GOARCH == "arm64") &&
		GOOS != "nacl" && useAeshash {
   
		return aeshash(p, seed, s)
	}
	h := uint64(seed + s*hashkey[0])
tail:
	switch {
   
	case s == 0:
	case s < 4:
		h ^= uint64(*(*byte)(p))
		h ^= uint64(*(*byte)(add(p, s>>1))) << 8
		h ^= uint64(*(*byte)(add(p, s-1))) << 16
		h = rotl_31(h*m1) * m2
	case s <= 8:
		h ^= uint64(readUnaligned32(p))
		h ^= uint64(readUnaligned32(add(p, s-
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值