一、map初始化赋值

Go语言中的map是一种无序的键值集合,非常灵活方便,适用于需要建立键值关系的场景。它的初始化和赋值操作相对简单

1、初始化map

使用make函数来初始化一个map语法如下

mapVariable := make(map[KeyType]ValueType)

其中,KeyType是键的类型ValueType是值的类型。例如:

studentAges := make(map[string]int)

这样就创建一个空的map用于存储学生年龄信息

2、赋值和访问map

可以使用键来为map赋值和访问值。赋值的语法为:

mapVariable[key] = value

访问的语法为:

value = mapVariable[key]

示例

// 初始化map
studentAges := make(map[string]int)

// 赋值
studentAges["Alice"] = 20
studentAges["Bob"] = 22
studentAges["Charlie"] = 21

// 访问
aliceAge := studentAges["Alice"]
bobAge := studentAges["Bob"]
charlieAge := studentAges["Charlie"]

fmt.Println("Alice's Age:", aliceAge)
fmt.Println("Bob's Age:", bobAge)
fmt.Println("Charlie's Age:", charlieAge)

在这个例子中,我们首先初始化了一个map然后每个学生赋值其年龄最后通过键来访问相应的值,并打印出来。输出结果应该是:

Alice's Age: 20
Bob's Age: 22
Charlie's Age: 21

3、判断是否存在

使用map时,有时候我们需要判断某个键是否存在map中。可以使用多重赋值的方式判断

value, ok := mapVariable[key]

如果key存在ok的值为true,否则为false

// 判断是否存在
age, exists := studentAges["David"]
if exists {
    fmt.Println("David's Age:", age)
} else {
    fmt.Println("David's Age not found.")
}

这样我们就可以根据exists的值来判断是否存在,避免因为不存在的键而引发错误

二、map进行for循环遍历

在Go语言中,使用for循环遍历map可以通过range关键字实现range返回两个值,分别是keyvalue

示例

package main

import "fmt"

func main() {
    // 初始化map
    studentAges := map[string]int{
        "Alice":   20,
        "Bob":     22,
        "Charlie": 21,
    }

    // 使用for循环遍历map
    for name, age := range studentAges {
        fmt.Printf("%s's Age: %dn", name, age)
    }
}

在这个例子中,我们首先初始化了一个map然后使用for循环range关键字遍历这个map。在每次循环中,name会得到键,age会得到对应的值,然后我们打印出来。

输出结果应该是:

Alice's Age: 20
Bob's Age: 22
Charlie's Age: 21

这样,我们就成功地遍历了map的所有键值对。需要注意的是,map是无序的,所以遍历的顺序可能不同于初始化时的顺序。如果需要按照特定顺序遍历,可以先将键排序后再遍历。

三、map进行for循环遍历可能存在的坑

使用Go语言for循环遍历map时,可能会遇到以下一些潜在的问题

1、并发读写导致的竞态条件

多个goroutine同时读写map时可能导致竞态条件,因为Go中的map不是并发安全的。即使一个goroutine在遍历map的时候,另一个goroutine修改map内容,就可能导致遍历出现未定义行为

示例

package main

import (
	"fmt"
	"sync"
	"time"
)

func main() {
	myMap := make(map[string]int)
	var wg sync.WaitGroup

	// 并发写入
	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < 5; i++ {
			myMap[fmt.Sprintf("key%d", i)] = i
			time.Sleep(time.Millisecond * 10) // 模拟写入过程
		}
	}()

	// 并发读取
	wg.Add(1)
	go func() {
		defer wg.Done()
		for key, value := range myMap {
			fmt.Printf("Read - Key: %s, Value: %dn", key, value)
		}
	}()

	wg.Wait()
}

解释
在这个例子中,一个goroutine在不断往map中写数据,而另一个goroutine在遍历map。由于写入过程存在延迟,可能导致遍历时读到不一致的数据

2、删除元素导致的遍历问题

在遍历map的过程中删除元素可能会导致迭代失效,引发运行错误

示例

package main

import "fmt"

func main() {
	myMap := map[string]int{
		"A": 1,
		"B": 2,
		"C": 3,
	}

	for key, value := range myMap {
		fmt.Printf("Key: %s, Value: %dn", key, value)
		if key == "B" {
			delete(myMap, key) // 在遍历时删除元素
		}
	}
}

解释
在这个例子中,当遍历到键为”B”的时候删除了该元素,这可能导致迭代失效,从而引发运行错误

3、解决方案

  1. 使用互斥锁: 在并发场景下,使用sync.Mutex同步机制来保护map,确保同一时间只有一个goroutine在对其进行读写操作

  2. 复制map: 在遍历map时,复制内容到一个新的map切片中,再进行操作,避免在遍历过程中对原map进行修改

  3. 遍历时删除元素: 如果需要在遍历过程中删除元素,可以记录要删除的元素的键,遍历完成后再进行删除操作,或者使用一个新的map保存要删除的键。

  4. 使用并发安全sync.Map Go语言提供了sync.Map,它是并发安全的,可以多个goroutine中安全地读写

package main

import (
	"fmt"
	"sync"
)

func main() {
	myMap := &amp;sync.Map{}
	var wg sync.WaitGroup

	// 并发写入
	wg.Add(1)
	go func() {
		defer wg.Done()
		for i := 0; i < 5; i++ {
			myMap.Store(fmt.Sprintf("key%d", i), i)
		}
	}()

	// 并发读取
	wg.Add(1)
	go func() {
		defer wg.Done()
		myMap.Range(func(key, value interface{}) bool {
			fmt.Printf("Read - Key: %s, Value: %vn", key, value)
			return true
		})
	}()

	wg.Wait()
}

四、判断map中是否存在元素和删除元素

1、判断map中是否存在元素

在Go语言中,判断map是否存在某个元素可以使用两个返回值的方式,第一个返回值是元素的值,第二个返回值是一个布尔值,表示元素是否存在。

package main

import "fmt"

func main() {
    // 创建一个map
    myMap := map[string]int{
        "A": 1,
        "B": 2,
        "C": 3,
    }

    // 判断元素是否存在
    key := "B"
    value, exists := myMap[key]
    if exists {
        fmt.Printf("Key %s exists, Value: %dn", key, value)
    } else {
        fmt.Printf("Key %s does not existn", key)
    }

    // 不存在的情况
    key = "D"
    value, exists = myMap[key]
    if exists {
        fmt.Printf("Key %s exists, Value: %dn", key, value)
    } else {
        fmt.Printf("Key %s does not existn", key)
    }
}

在这个例子中,exists表示是否存在,如果存在,则打印出键对应的值,否则打印不存在的消息

结果

Key B exists, Value: 2
Key D does not exist

2、删除map中的元素

删除map中的元素可以使用delete函数

package main

import "fmt"

func main() {
    // 创建一个map
    myMap := map[string]int{
        "A": 1,
        "B": 2,
        "C": 3,
    }

    // 删除指定元素
    key := "B"
    fmt.Printf("Before deletion: %vn", myMap)
    
    // 判断元素是否存在,存在则删除
    if _, exists := myMap[key]; exists {
        delete(myMap, key)
        fmt.Printf("Key %s deletedn", key)
    } else {
        fmt.Printf("Key %s does not existn", key)
    }

    fmt.Printf("After deletion: %vn", myMap)

    // 尝试删除不存在的元素
    key = "D"
    fmt.Printf("Before deletion: %vn", myMap)
    delete(myMap, key)
    fmt.Printf("After deletion: %vn", myMap)
}

在这个例子中,首先判断要删除的元素是否存在,如果存在,则使用delete函数删除该元素。在第二次删除时,尝试删除一个不存在的元素,不会引发错误delete操作会被忽略

结果

Before deletion: map[A:1 B:2 C:3]
Key B deleted
After deletion: map[A:1 C:3]
Before deletion: map[A:1 C:3]
After deletion: map[A:1 C:3]

原文地址:https://blog.csdn.net/weixin_49015143/article/details/134596077

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_17323.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注