欢迎光临
我们一直在努力

了解Go中的地图

大多数现代编程语言都具有字典散列类型的概念。 这些类型通常用于与映射到成对存储数据。

在Go中, 地图数据类型是大多数程序员所能想到的字典类型。 它将键映射到值,使键值对成为在Go中存储数据的有用方法。 通过使用关键字map后跟方括号[ ]的键数据类型,后跟值数据类型来构造map 然后将键值对放在任一侧{}的花括号内:

map[key]value{}

您通常使用Go中的映射来保存相关数据,例如ID中包含的信息。 包含数据的地图如下所示:

map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

除了花括号外,整个地图中还有冒号连接键值对。 冒号左边的单词是键。 键可以是Go中的任何类似类型,如stringsints等。

示例映射中的键是:

  • "name"
  • "animal"
  • "color"
  • "location"

冒号右边的单词是值。 值可以是任何数据类型。 示例映射中的值为:

  • "Sammy"
  • "shark"
  • "blue"
  • "ocean"

与其他数据类型一样,您可以将地图存储在变量中,然后将其打印出来:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}fmt.Println(sammy)

这将是你的输出:

map[animal:shark color:blue location:ocean name:Sammy]

键值对的顺序可能已经移位。 在Go中,地图数据类型是无序的。 无论顺序如何,键值对都将保持不变,使您能够根据其关系含义访问数据。

访问地图项目

您可以通过引用相关键来调用映射的值。 由于地图提供了用于存储数据的键值对,因此它们可能是Go程序中的重要且有用的项目。

如果你想隔离Sammy的用户名,可以通过调用sammy["name"] ; 保存地图和相关密钥的变量。 让我们打印出来:

fmt.Println(sammy["name"])

并获得输出值:

Sammy

地图的行为类似于数据库; 而不是像调整切片一样调用整数来获取特定的索引值,而是为键分配值并调用该键以获取其相关值。

通过调用键"name"您将获得该键的值,即"Sammy"

同样,您可以使用相同的格式调用sammy地图中的剩余值:

fmt.Println(sammy["animal"])// returns sharkfmt.Println(sammy["color"])// returns bluefmt.Println(sammy["location"])// returns ocean

通过使用地图数据类型中的键值对,您可以引用键来检索值。

键和值

与某些编程语言不同,Go没有任何便利功能来列出地图的键或值。 这方面的一个例子是Python用于字典的.keys()方法。 但是,它确实允许使用range运算符进行迭代:

for key, value := range sammy {    fmt.Printf("%q is the key for the value %q\n", key, value)}

通过Go中的地图进行测距时,它将返回两个值。 第一个值是键,第二个值是值。 Go将使用正确的数据类型创建这些变量。 在这种情况下,map键是一个string因此key也将是一个字符串。 value也是一个字符串:

"animal" is the key for the value "shark""color" is the key for the value "blue""location" is the key for the value "ocean""name" is the key for the value "Sammy"

要获得仅键列表,可以再次使用范围运算符。 您只能声明一个变量来访问键:

keys := []string{}for key := range sammy {    keys = append(keys, key)}fmt.Printf("%q", keys)

该程序首先声明一个切片来存储您的密钥。

输出将仅显示地图的键:

["color" "location" "name" "animal"]

同样,密钥没有排序。 如果要对它们进行排序,可以使用sort包中的sort.Strings函数:

sort.Strings(keys)

使用此功能,您将收到以下输出:

["animal" "color" "location" "name"]

您可以使用相同的模式仅检索地图中的值。 在下一个示例中,您预先分配切片以避免分配,从而使程序更有效:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}items := make([]string, len(sammy))var i intfor _, v := range sammy {    items[i] = v    i++}fmt.Printf("%q", items)

首先,您声明一个切片来存储您的密钥; 既然您知道需要多少项,就可以通过以完全相同的大小定义切片来避免潜在的内存分配。 然后,您声明索引变量。 由于您不需要密钥,因此在启动循环时使用_运算符忽略密钥的值。 您的输出将如下:

["ocean" "Sammy" "shark" "blue"]

要确定地图中的项目数,可以使用内置的len函数:

sammy := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}fmt.Println(len(sammy))

输出显示地图中的项目数:

4

尽管Go没有提供方便函数来获取键和值,但只需要几行代码就可以在需要时检索键和值。

检查存在

当请求的密钥丢失时,Go中的地图将返回地图值类型的零值。 因此,您需要一种替代方法来区分存储的零和缺少的密钥。

让我们在你知道不存在的地图中查找一个值并查看返回的值:

counts := map[string]int{}fmt.Println(counts["sammy"])

您将看到以下输出:

0

即使关键的sammy不在地图中,Go仍然返回值0 这是因为值数据类型是int ,并且因为Go对所有变量都具有零值,所以它返回零值0

在许多情况下,这是不可取的,会导致程序中的错误。 在地图中查找值时,Go可以返回第二个可选值。 第二个值是bool ,如果找到密钥则为false如果未找到密钥则为false 在Go中,这被称为ok惯用语。 即使您可以将捕获第二个参数的变量命名为Go,但在Go中,您总是将其命名为ok

count, ok := counts["sammy"]

如果关键的sammy存在于counts图中,则ok将为true 否则ok会是假的。

您可以使用ok变量来决定程序中的操作:

if ok {    fmt.Printf("Sammy has a count of %d\n", count)} else {    fmt.Println("Sammy was not found")}

这将导致以下输出:

Sammy was not found

在Go中,您可以将变量声明和条件检查与if / else块组合在一起。 这允许您使用单个语句进行此检查:

if count, ok := counts["sammy"]; ok {    fmt.Printf("Sammy has a count of %d\n", count)} else {    fmt.Println("Sammy was not found")}

从Go中的地图中检索值时,最好还是检查它的存在,以避免程序中出现错误。

修改地图

地图是一种可变数据结构,因此您可以修改它们。 我们来看看在本节中添加和删除地图项目。

添加和更改地图项目

不使用方法或函数,可以向地图添加键值对。 您可以使用maps变量名称,后跟方括号[ ]的键值,并使用equal =运算符设置新值:

map[key] = value

实际上,您可以通过向名为usernames的地图添加键值对来查看此工作:

usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}usernames["Drew"] = "squidly"fmt.Println(usernames)

输出将在地图中显示新的Drew:squidly键值对:

map[Drew:squidly Jamie:mantisshrimp54 Sammy:sammy-shark]

由于地图是无序返回的,因此该对可能出现在地图输出中的任何位置。 如果稍后在程序文件中使用usernames映射,则它将包含其他键值对。

您还可以使用此语法修改分配给键的值。 在这种情况下,您引用现有密钥并向其传递不同的值。

考虑一个名为followers的地图,跟踪给定网络上用户的关注者。 用户"drew"今天的粉丝有一个碰撞,所以你需要更新传递给"drew"键的整数值。 您将使用Println()函数检查地图是否已被修改:

followers := map[string]int{"drew": 305, "mary": 428, "cindy": 918}followers["drew"] = 342fmt.Println(followers)

您的输出将显示drew的更新值:

map[cindy:918 drew:342 mary:428]

您会看到关注者的数量从305的整数值跳到342

您可以使用此方法将键值对添加到具有用户输入的地图。 让我们编写一个名为usernames.go的快速程序,该程序在命令行上运行,并允许用户输入以添加更多名称和关联的用户名:

usernames.go
package mainimport (    "fmt"    "strings")func main() {    usernames := map[string]string{"Sammy": "sammy-shark", "Jamie": "mantisshrimp54"}    for {        fmt.Println("Enter a name:")        var name string        _, err := fmt.Scanln(&name)        if err != nil {            panic(err)        }        name = strings.TrimSpace(name)        if u, ok := usernames[name]; ok {            fmt.Printf("%q is the username of %q\n", u, name)            continue        }        fmt.Printf("I don't have %v's username, what is it?\n", name)        var username string        _, err = fmt.Scanln(&username)        if err != nil {            panic(err)        }        username = strings.TrimSpace(username)        usernames[name] = username        fmt.Println("Data updated.")    }}

usernames.go ,首先定义原始地图。 然后,您设置一个循环来迭代名称。 您请求您的用户输入一个名称并声明一个变量来存储它。接下来,检查您是否有错误; 如果是这样,该程序将以恐慌退出。 因为Scanln捕获整个输入,包括回车,所以你需要从输入中删除任何空间; 你用strings.TrimSpace函数做到这一点。

if块检查地图中是否存在名称并打印反馈。 如果名称存在,则继续返回循环的顶部。 如果名称不在地图中,则会向用户提供反馈,然后会为相关名称请求新的用户名。 程序再次检查是否有错误。 没有错误,它会修剪回车符,将用户名值分配给名称键,然后打印数据已更新的反馈。

让我们在命令行上运行程序:

go run usernames.go

您将看到以下输出:

Enter a name:Sammy"sammy-shark" is the username of "Sammy"Enter a name:JesseI don't have Jesse's username, what is it?JOctopusData updated.Enter a name:

完成测试后,按CTRL + C退出程序。

这显示了如何以交互方式修改地图。 使用此特定程序,只要您使用CTRL + C退出程序,除非您实现处理读取和写入文件的方法,否则您将丢失所有数据。

总而言之,您可以使用map[key] = value语法将项目添加到地图或修改值。

删除地图项目

就像您可以在地图数据类型中添加键值对和更改值一样,您也可以删除地图中的项目。

要从地图中删除键值对,可以使用内置函数delete() 第一个参数是您要删除的地图。 第二个参数是您要删除的键:

delete(map, key)

让我们定义一个权限地图:

permissions := map[int]string{1: "read", 2: "write", 4: "delete", 8: "create", 16:"modify"}

您不再需要modify权限,因此您将从地图中删除它。 然后你会打印出地图以确认它被删除了:

permissions := map[int]string{1: "read", 2: "write", 4: "delete", 8: "create", 16: "modify"}delete(permissions, 16)fmt.Println(permissions)

输出将确认删除:

map[1:read 2:write 4:delete 8:create]

delete(permissions, 16)permissions映射中删除键值对16:"modify"

如果要清除其所有值的映射,可以通过将其设置为相同类型的空映射来实现。 这将创建一个新的空映射使用,旧映射将由垃圾收集器从内存中清除。

让我们删除permissions映射中的所有项目:

permissions = map[int]string{}fmt.Println(permissions)

输出显示您现在有一个没有键值对的空映射:

map[]

由于映射是可变数据类型,因此可以添加,修改它们,并删除和清除项目。

结论

本教程探讨了Go中的地图数据结构。 映射由键值对组成,提供了一种存储数据的方法,而不依赖于索引。 这允许我们根据其含义以及与其他数据类型的关系来检索值。

赞(0) 打赏
未经允许不得转载:老赵部落 » 了解Go中的地图

评论 抢沙发