Map实战 #

一、计数器模式 #

1.1 单词计数 #

go
func wordCount(text string) map[string]int {
    words := strings.Fields(text)
    counts := make(map[string]int)
    for _, word := range words {
        counts[strings.ToLower(word)]++
    }
    return counts
}

text := "hello world hello go world"
fmt.Println(wordCount(text))
// map[hello:2 world:2 go:1]

1.2 字符频率统计 #

go
func charFrequency(s string) map[rune]int {
    freq := make(map[rune]int)
    for _, r := range s {
        freq[r]++
    }
    return freq
}

1.3 投票计数 #

go
type VoteCounter struct {
    counts map[string]int
    mu     sync.RWMutex
}

func NewVoteCounter() *VoteCounter {
    return &VoteCounter{
        counts: make(map[string]int),
    }
}

func (vc *VoteCounter) Vote(candidate string) {
    vc.mu.Lock()
    defer vc.mu.Unlock()
    vc.counts[candidate]++
}

func (vc *VoteCounter) GetCount(candidate string) int {
    vc.mu.RLock()
    defer vc.mu.RUnlock()
    return vc.counts[candidate]
}

func (vc *VoteCounter) GetResults() map[string]int {
    vc.mu.RLock()
    defer vc.mu.RUnlock()
    result := make(map[string]int)
    for k, v := range vc.counts {
        result[k] = v
    }
    return result
}

二、缓存模式 #

2.1 简单缓存 #

go
type Cache struct {
    data map[string]interface{}
    mu   sync.RWMutex
}

func NewCache() *Cache {
    return &Cache{
        data: make(map[string]interface{}),
    }
}

func (c *Cache) Get(key string) (interface{}, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    v, ok := c.data[key]
    return v, ok
}

func (c *Cache) Set(key string, value interface{}) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.data[key] = value
}

func (c *Cache) Delete(key string) {
    c.mu.Lock()
    defer c.mu.Unlock()
    delete(c.data, key)
}

2.2 带过期时间的缓存 #

go
type CacheItem struct {
    Value      interface{}
    Expiration time.Time
}

type TTLCache struct {
    data map[string]CacheItem
    mu   sync.RWMutex
}

func (c *TTLCache) Get(key string) (interface{}, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    
    item, ok := c.data[key]
    if !ok {
        return nil, false
    }
    
    if time.Now().After(item.Expiration) {
        return nil, false
    }
    
    return item.Value, true
}

func (c *TTLCache) Set(key string, value interface{}, ttl time.Duration) {
    c.mu.Lock()
    defer c.mu.Unlock()
    
    c.data[key] = CacheItem{
        Value:      value,
        Expiration: time.Now().Add(ttl),
    }
}

三、分组模式 #

3.1 按字段分组 #

go
type Person struct {
    Name string
    City string
    Age  int
}

func groupByCity(people []Person) map[string][]Person {
    groups := make(map[string][]Person)
    for _, p := range people {
        groups[p.City] = append(groups[p.City], p)
    }
    return groups
}

3.2 通用分组函数 #

go
func GroupBy[T any, K comparable](items []T, keyFunc func(T) K) map[K][]T {
    groups := make(map[K][]T)
    for _, item := range items {
        key := keyFunc(item)
        groups[key] = append(groups[key], item)
    }
    return groups
}

people := []Person{
    {"Alice", "Beijing", 25},
    {"Bob", "Shanghai", 30},
    {"Carol", "Beijing", 28},
}

groups := GroupBy(people, func(p Person) string {
    return p.City
})

四、索引模式 #

4.1 ID索引 #

go
type User struct {
    ID   int
    Name string
}

func buildUserIndex(users []User) map[int]User {
    index := make(map[int]User)
    for _, u := range users {
        index[u.ID] = u
    }
    return index
}

func findUser(index map[int]User, id int) (User, bool) {
    u, ok := index[id]
    return u, ok
}

4.2 多字段索引 #

go
type UserDB struct {
    byID   map[int]*User
    byName map[string]*User
    mu     sync.RWMutex
}

func NewUserDB() *UserDB {
    return &UserDB{
        byID:   make(map[int]*User),
        byName: make(map[string]*User),
    }
}

func (db *UserDB) Add(u *User) {
    db.mu.Lock()
    defer db.mu.Unlock()
    db.byID[u.ID] = u
    db.byName[u.Name] = u
}

func (db *UserDB) FindByID(id int) (*User, bool) {
    db.mu.RLock()
    defer db.mu.RUnlock()
    u, ok := db.byID[id]
    return u, ok
}

func (db *UserDB) FindByName(name string) (*User, bool) {
    db.mu.RLock()
    defer db.mu.RUnlock()
    u, ok := db.byName[name]
    return u, ok
}

五、集合模式 #

5.1 使用Map实现集合 #

go
type Set map[string]struct{}

func NewSet(items ...string) Set {
    s := make(Set)
    for _, item := range items {
        s[item] = struct{}{}
    }
    return s
}

func (s Set) Add(item string) {
    s[item] = struct{}{}
}

func (s Set) Remove(item string) {
    delete(s, item)
}

func (s Set) Contains(item string) bool {
    _, ok := s[item]
    return ok
}

func (s Set) ToSlice() []string {
    result := make([]string, 0, len(s))
    for item := range s {
        result = append(result, item)
    }
    return result
}

5.2 集合运算 #

go
func Union(s1, s2 Set) Set {
    result := make(Set)
    for k := range s1 {
        result[k] = struct{}{}
    }
    for k := range s2 {
        result[k] = struct{}{}
    }
    return result
}

func Intersection(s1, s2 Set) Set {
    result := make(Set)
    for k := range s1 {
        if s2.Contains(k) {
            result[k] = struct{}{}
        }
    }
    return result
}

func Difference(s1, s2 Set) Set {
    result := make(Set)
    for k := range s1 {
        if !s2.Contains(k) {
            result[k] = struct{}{}
        }
    }
    return result
}

六、配置管理 #

6.1 配置存储 #

go
type Config struct {
    data map[string]interface{}
    mu   sync.RWMutex
}

func NewConfig() *Config {
    return &Config{
        data: make(map[string]interface{}),
    }
}

func (c *Config) GetString(key string) string {
    c.mu.RLock()
    defer c.mu.RUnlock()
    if v, ok := c.data[key]; ok {
        return v.(string)
    }
    return ""
}

func (c *Config) GetInt(key string) int {
    c.mu.RLock()
    defer c.mu.RUnlock()
    if v, ok := c.data[key]; ok {
        return v.(int)
    }
    return 0
}

func (c *Config) Set(key string, value interface{}) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.data[key] = value
}

七、总结 #

Map实战要点:

模式 应用场景
计数器 统计频率、投票
缓存 数据缓存、结果缓存
分组 数据分类
索引 快速查找
集合 去重、集合运算

关键点:

  1. 并发安全:使用sync.RWMutex保护Map
  2. 性能优化:预分配容量
  3. 内存管理:及时清理不需要的数据
  4. 类型安全:使用泛型提高类型安全

准备好学习字符串了吗?让我们进入下一章!

最后更新:2026-03-26