[go]map

//map的结构
//runtime/map.go: 一个map的类型如下: 由多个bmap组成buckets, 数据存在于bmap中

// A header for a Go map.
type hmap struct {
	// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
	// Make sure this stays in sync with the compiler's definition.
	count     int // # live cells == size of map.  Must be first (used by len() builtin)
	flags     uint8
	B         uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
	noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
	hash0     uint32 // hash seed

	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)

	extra *mapextra // optional fields
}



// A bucket for a Go map.
type bmap struct {
	// tophash generally contains the top byte of the hash value
	// for each key in this bucket. If tophash[0] < minTopHash,
	// tophash[0] is a bucket evacuation state instead.
	tophash [bucketCnt]uint8
	// Followed by bucketCnt keys and then bucketCnt elems.
	// NOTE: packing all the keys together and then all the elems together makes the
	// code a bit more complicated than alternating key/elem/key/elem/... but it allows
	// us to eliminate padding which would be needed for, e.g., map[int64]int8.
	// Followed by an overflow pointer.
}
//map是引用类型
// 默认为初始化值为nil, 要使用必须先(make)初始化开辟内存
func main() {
	var m map[string]int
	fmt.Println(m == nil)
}

//true
//nil map: 要使用,必须先初始化.
func main() {
	var m map[string]int
	m["m1"] = 1
}
//panic: assignment to entry in nil map
//内容为空的map: 内存已开辟好,可直接使用
func main() {
	m := make(map[string]int)
	m["m1"] = 1
}

//或
func main() {
	m := map[string]int{}
	m["m1"] = 1
}
//定义map: 声明并初始化(crud)
func main() {
	m := map[string]int{
		"m1": 1,
	}

	fmt.Println(m["m1"]) //查询
	m["a"] = 11          //添加/更新

	delete(m, "m1") //删除,key不存在时,不会报错
	delete(m, "m2")

	v, ok := m["m2"] //判断key是否存在
	fmt.Println(v, ok)
}

//1
//0 false
// 切片中存map类型
func main() {
	rand.Seed(time.Now().UnixNano())
	var arr []map[string]int
	arr = make([]map[string]int, 10)

	for i := 0; i < 10; i++ {
		//初始化key
		arr[i] = make(map[string]int)
		arr[i]["m1"] = 10
		arr[i]["m2"] = 20
	}
	fmt.Println(arr)
}
// map中存切片

func main() {
	var m map[string][]int
	//初始化map
	m = make(map[string][]int, 0)
	
	for i := 0; i < 10; i++ {

		key := fmt.Sprintf("user%v", i)
		if _, ok := m[key]; !ok {
			//初始化key
			m[key] = make([]int, 5)
			for j := 0; j < 5; j++ {
				m[key][j] = j * 10
			}
		}
	}
	fmt.Println(m)
}
//map元素的值为匿名结构体: 声明+初始化(可以看到赋值时还是比较麻烦)
func main() {
	m := map[string]struct {
		name string
		age  int
	}{
		"item1": struct {
			name string
			age  int
		}{name: "m1", age: 22},
	}
	fmt.Println(m)
}

//map[item1:{m1 22}]
//map元素的值为匿名结构体: 先声明,后初始化
func main() {
	//声明
	var m map[string]struct {
		name string
		age  int
	}

	//初始化
	m = make(map[string]struct {
		name string
		age  int
	})
	//增加项
	m["item1"] = struct {
		name string
		age  int
	}{name: "m1", age: 22}

	fmt.Println(m)
}

//map[item1:{m1 22}]

// 结构体初始化时: key可以省略
func main() {
	m := map[string]struct {
		name string
		age  int
	}{
		"item1": struct {
			name string
			age  int
		}{"m1",22}, //{name: "m1", age: 22} -> {"m1", 22} key可以省略
	}
	fmt.Println(m)
}
//map元素的值为结构体
func main() {
	type user struct {
		name string
		age  int
	}
	m := map[int]user{
		1: {"tom", 19},
	}
	fmt.Println(m)
}

//map[1:{tom 19}]
//map元素的值为结构体: 修改结构体项的值
func main() {
	type user struct {
		name string
		age  int
	}
	m := map[int]user{
		1: {"tom", 19},
	}
	m[1].age += 1
}

//.main.go:11:11: cannot assign to struct field m[1].age in map
//map元素的值为结构体: 修改结构体项的值
func main() {
	type user struct {
		name string
		age  int
	}
	m := map[int]user{
		1: {"tom", 19},
	}
	//修改map中k为1的结构体项的值
	// 1.先取出结构体实例
	u := m[1]
	// 2.修改结构体实例的值
	u.age = 1
	// 3.更新map
	m[1] = u
	fmt.Println(u)
}

//{tom 1}

小结: 当map的值为结构或数组时,要修改值,必须先返回对象, 因为struct/slice被设计为not addressable

//遍历map(Iterate over map): 每次运行结果无序的

func main() {
	rand.Seed(time.Now().UnixNano())

	var m map[string]int
	m = make(map[string]int, 0)
	//构建map
	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("user%v", i)
		m[key] = rand.Intn(1024)
	}
	
	//遍历map
	for k, v := range m {
		fmt.Println(k, v)
	}
}
//遍历map: 使key遍历有序
	1.取出key
	2.对key排序
	3.遍历map

func main() {
	rand.Seed(time.Now().UnixNano())

	var m map[string]int
	m = make(map[string]int, 0)
	//构建map
	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("user%v", i)
		m[key] = rand.Intn(1024)
	}

	//排序key
	keys := []string{}
	for k, _ := range m {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	//遍历map-结果有序
	for _, v := range keys {
		fmt.Println(v, m[v])
	}
}
//先计算range m 然后开启for循环
//即必须循环len(m)次
func main() {
	m := make(map[int]int)
	//初始化
	for i := 0; i < 5; i++ {
		m[i] = i + 10
	}
	for k := range m {
		fmt.Println(m, k)
	}
}
// 安全, 在迭代期间,删除或新增key是安全的.
// 1.range m计算迭代次数, 
// 2.开启for循环
// 3.delete(m, k) 将这个key的删除

func main() {
	m := make(map[int]int)
	//初始化
	for i := 0; i < 5; i++ {
		m[i] = i + 10
	}
	//打印初始化的map
	fmt.Println(m)
	//遍历
	for k := range m {
		delete(m, k)
		fmt.Println(m, k) //打印当前map
	}
}

//map[0:10 1:11 2:12 3:13 4:14]
//map[1:11 2:12 3:13 4:14] 0
//map[2:12 3:13 4:14] 1
//map[3:13 4:14] 2
//map[4:14] 3
//map[] 4
// 安全: 运行时对字段并发操作做出检测, 如果某个任务正在对字典进程读写操作,那么其他任务就不能对该字典执行读写.
func main() {
	m := map[string]int{}
	//写操作
	go func() {
		for {
			m["m1"] += 10
			time.Sleep(time.Microsecond)
		}
	}()
	//读操作
	go func() {
		for {
			_ = m["m1"]
			time.Sleep(time.Microsecond)
		}
	}()
	time.Sleep(time.Second)
}

//fatal error: concurrent map read and map write


// 安全: 可用sync.RWMutex实现同步,避免读写操作同时进行
func main() {
	var lock sync.RWMutex
	m := map[string]int{}
	//写操作
	go func() {
		for {
			lock.Lock()
			m["m1"] += 10
			time.Sleep(time.Microsecond)
		}
	}()
	//读操作
	go func() {
		for {
			lock.RLock()
			_ = m["m1"]
			time.Sleep(time.Microsecond)
		}
	}()
	time.Sleep(time.Second)
}
- 性能 开辟足够的空间
func test()map[int]int{ 
   m:=make(map[int]int) 
   for i:=0;i<1000;i++ { 
       m[i] =i
    } 
  
   return m
} 
  
func testCap()map[int]int{ 
   m:=make(map[int]int,1000)       // 预先准备足够的空间 
   for i:=0;i<1000;i++ { 
       m[i] =i
    } 
  
   return m
} 
//性能: 一次开辟足够空间,减少内存扩容和重新hash操作
func test()map[int]int{
   m:=make(map[int]int)
   for i:=0;i<1000;i++ {
       m[i] =i
    }

   return m
}

func testCap()map[int]int{
   m:=make(map[int]int,1000)       // 预先准备足够的空间
   for i:=0;i<1000;i++ {
       m[i] =i
    }

   return m
}

func BenchmarkTest(b*testing.B) {
   for i:=0;i<b.N;i++ {
       test()
    }
}

func BenchmarkTestCap(b*testing.B) {
   for i:=0;i<b.N;i++ {
       testCap()
    }
}
//BenchmarkTest-8            16448             72062 ns/op
//BenchmarkTestCap-8         40266             29741 ns/op
//性能: 对海量小对象,使用值类型,而非指针, 减少gc成本.

[go]map实现通讯录

原文地址:https://www.cnblogs.com/iiiiiher/p/12190108.html