学习Golang的教程--带例子的map指南

138 阅读10分钟

在本教程中,我们将通过实例学习Go语言中的地图内置类型。

Go语言地图教程

map 是一种流行的集合数据结构,包含keyvalue 对。 在其他编程语言中,它被用来表示hashtable和字典。

Java有HashTable, Python有Dictionary 类型。它提供了基于键的快速循环、搜索、更新、删除。

map在Go编程语言中的重要性:

  • 它是Golang中的内置类型
  • 它是一个无序的数据结构,包含键和值对
  • 一个地图不允许有重复的键,但可以有重复的值
  • 地图中的键是唯一的,值不需要。
  • 在其他编程语言中,这也被称为关联数组、哈希图或字典。
  • 键的类型只能是可比较的类型--不允许使用函数、地图、片断
  • 值类型是任何类型的--原始类型、自定义类型或接口{}类型

Golang中的地图语法

var variablename map[keytype]valuetype  

语法包含以下内容

Start avar 关键字,用于声明地图类型的变量。 variablename 是地图的变量名称。它应该是有效的标识符。

a map是使用的关键字,后面是方括号中声明的键类型和值类型。

如何声明一个地图变量并以值初始化

我们将看到各种创建和初始化地图的方法

带有nil类型的零值地图

在这种情况下,地图只被声明而不被初始化,这被称为零值地图。

零值地图的值是nil。它没有键和值。

下面是一个带有字符串键和int值的地图变量声明。

变量k是map类型的,将字符串值分配给整数。

// keys are of string type, values are of int type  
var k map[string]int; // map is nil value  

Map 类型是参考类型,如:k的值是nil,没有指向性,但是,slices初始化的地图. 以下是一个例子

package main  
import (  
 "fmt"  
)  
func main() {  
 var mymap map[string]int  
 fmt.Println(mymap)  
 if mymap == nil {  
  fmt.Println("map is nil")  
 }  
  
}  

输出是

map[]  
map is nil  

当你向nil地图添加值时,它给出了运行时错误--panic: assignment to entry in nil map.

一个地图应该总是被初始化,以便向它添加元素。

下面是一个向地图添加元素的例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 var mymap map[string]int  
 fmt.Println(mymap)  
 if mymap == nil {  
  fmt.Println("map is nil")  
 }  
 mymap["kiran"] = 1 // this gives runtime error  
}  

输出是

map[]  
map is nil  
panic: assignment to entry in nil map  
  
goroutine 1 [running]:  
main.main()  
        A:/Golang/work/Test.go:13 +0xd3  
exit status 2  

使用内置的make函数创建地图

你可以使用内置的make() 函数来创建一个地图。make函数分配hashmap数据结构,返回一个引用它的地图。

这个make函数接受地图的类型和容量。这将创建一个地图并以空元素进行初始化。
下面是make函数的一个语法

make(map[keytype]valuetype, optional capacity)  

这个函数接受地图的类型和可选的初始容量,我们可以在下面的例子中覆盖默认容量。

var mymap=make(map[string]int)  
1:= make(map[string]int, 20)  

上面的代码创建了一个名为mymap的地图,它接受字符串的键和int类型的值。

这就是所谓的空地图。在读取元素时,nil地图的作用与空地图相同。

当试图添加元素到Nil Map ,运行时出现了恐慌。当添加元素时,空地图的工作方式与预期相同。

上面这行代码可以通过使用shorthand assignment operator (:=) ,用简短的变量声明来重写。
以下是新的语法

mymap:=make(map[string]int)  

以下是make函数的一个例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 var mymap = make(map[string]int)  
 fmt.Println(mymap)  
 if mymap == nil {  
  fmt.Println("map is nil")  
 } else {  
  fmt.Println("map is not nil")  
  
 }  
 mymap["kiran"] = 1 // map is initilzed, can add elements to it  
 fmt.Println(mymap)  
  
}  

输出是

map[]  
map is not nil  
map[kiran:1]  

使用地图字头创建和初始化

一个地图也可以用带有初始键和值的地图字头来创建。

例如,让我们创建一个空地图。这就创建了一个空地图,等同于make(map[string]int)函数。

var mymap = map[string]int{} 

这创建了一个初始化的空地图,并准备接受要添加的值。

下面是一个填充初始数据的例子。

这将通过在大括号{}内用冒号分隔的key和value来创建。

var mymap = map[string]int{  
 "Kiran": 1,  
 "John": 2,  
 "Frank": 3, // comma is required   
}  

地图字面的最后一个逗号是必须的,如果省略了逗号,会产生编译错误 - syntax error: unexpected newline, expecting comma or }

下面是一个完整的例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 var mymap1 = map[string]int{} // Create and initialize Empty Map  
 fmt.Println(mymap1)  
 // Create and initialize iniitial data using map literal   
 var mymap = map[string]int{  
  "Kiran": 1,  
  "John":  2,  
  "Frank": 3,  
 }  
 fmt.Println(mymap)  
  
}  

输出是

map[]  
map[Kiran:1 John:2 Frank:3]  

将元素(键值对)添加到地图中

一旦地图被创建,你可以使用以下语法向地图添加元素。

这个语法类似于Golang中的数组和片断。

上面这行代码将键设置为地图的值。如果你试图添加一个已经存在的键,它会将其值更新为新值

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map  
 var employees = make(map[int]string)  
  
 // Adding elements to a map  
 employees[1] = "kiran"  
 employees[2] = "Frank"  
 employees[3] = "John"  
  
 fmt.Println(employees)  
 /*  
    This overrides its value when key already exists in a map  
 */  
 employees[1] = "Ram"  
 fmt.Println(employees)  
  
}  

输出是

map[1:kiran 2:Frank 3:John]  
map[1:Ram 2:Frank 3:John]  

上面的例子使用make()函数创建和初始化,并添加一些元素。如果一个键已经存在,它将覆盖其值。在一个地图中获取具有给定键的项目或值。你可以使用下面的语法来检索基于键的值

value := mapvariable[ key ]  

如果地图包含键,则检索值,如果不包含,则返回地图值类型的非零值(0代表int,"" 代表string,0.0代表float类型)。
下面是一个访问地图项目的例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map  
 var employees = make(map[int]string)  
  
 // Adding elements to a map  
 employees[1] = "kiran"  
 employees[2] = "Frank"  
 employees[3] = "John"  
  
 fmt.Println(employees)  
 var name = employees[1]  
 fmt.Println("Key exist case ", name)  
 name1 := employees[11]  
 fmt.Println("Key not exist case: ", name1)  
}  

输出是

map[1:kiran 2:Frank 3:John]  
Key exist case  kiran  
Key not exist case:  

在上面的程序中,key=1已经存在于地图中,相应的值=kiran被返回。key=2不存在于地图中,我们得到地图值类型的零值,这里的地图值类型是字符串,空字符串""被返回。
,我们如何发现一个键在地图中是否存在?我们可以使用两个值分配地图检索语法区分空值和不存在的键。

如何检查地图是否包含一个键

Go语言为检索值提供了两种赋值语法。在map[key]语法中,它提供了额外的布尔标志--true,如果存在于地图中,false--key不存在于地图中

ok是一个布尔值--如果键存在则为真,不存在则为假 检查键是否存在于地图中的完整例子

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map  
 var employees = make(map[int]string)  
  
 // Adding elements to a map  
 employees[1] = "kiran"  
 employees[2] = "Frank"  
 employees[3] = "John"  
  
 fmt.Println(employees)  
 name, flag := employees[1]  
 fmt.Printf("key:1 value: %s flag: %v\n", name, flag)  
 name1, flag := employees[11]  
 fmt.Printf("key:11 value: %s flag: %v\n", name1, flag)  
}  

上述代码的输出是

map[1:kiran 2:Frank 3:John]  
key:1 value: kiran flag: true  
key:11 value:  flag: false  

在上面的例子中,检索key=1,该键存在于地图中,返回值=kiran,ok=true 检索key=11,该键不存在于地图中,返回值类型为零,即value="",ok=false。
,你可以用空白标识符(_)代替value来省略value域。

如何计算地图的大小 - 内置len()函数

您可以使用内置的len()函数计算地图中的项目或键的数量 语法如下

len()函数返回地图中的项目数,nil或空地图总是返回0。

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map  
 var employees = make(map[int]string) // nil map  
 fmt.Println(employees)  
 fmt.Println("Size: ", len(employees))  
  
 // Adding elements to a map  
 employees[1] = "kiran"  
 employees[2] = "Frank"  
 employees[3] = "John"  
  
 fmt.Println(employees)  
 fmt.Println("Size: ", len(employees))  
  
}  

输出是

`map[]  
Size:  0  
map[1:kiran 2:Frank 3:John]  
Size:  3  
`  

如何从地图中删除项目 - 内置删除函数

内置delete函数()用于从地图中删除一个项目。以下是这个函数的语法

这个函数删除了带有给定键的项目。如果键在地图中不存在,它不会返回任何值。

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map using map literal  
 employees := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
  
 fmt.Println(employees)  
 fmt.Println("Size: ", len(employees))  
 delete(employees, 1)  
 fmt.Println(employees)  
 fmt.Println("Size: ", len(employees))  
  
}  

上面的代码从地图中删除key=1,输出如下

map[1:ram 2:arun 3:Gef]  
Size:  3  
map[2:arun 3:Gef]  
Size:  2  

遍历地图的所有项目--for循环的范围形式

Map 使用带有range关键字的for循环对项目进行迭代。它返回每个迭代项的键和值。如果在迭代过程中没有迭代的条目被添加或删除,相应的条目将不会被考虑。

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map using map literal  
 employees := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
 for key, value := range employees {  
  fmt.Println(key, value)  
  
 }  
  
}  

由于map是一个无序的数据结构,所以顺序不被保证。当你运行上述程序时,多个输出顺序可能会改变。

下面是关于使用引用和值复制地图的内容

地图复制是参考类型

地图是像切片一样的参考类型,意思是地图只是分配的数据结构数据的参考点。当一个地图被分配给新的地图时,两个地图都指向同一个数据结构。如果一个地图有任何变化,都会反映在其他地图上。当地图被传递给函数时,这很有帮助,函数中的任何变化,函数调用者都会反映在地图中的变化。

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map using map literal  
 employees := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
 employees[4] = "jack"  
 fmt.Println("original map: ", employees)  
 newEmployees := employees  
 newEmployees[4] = "herald"  
 fmt.Println("new  map: ", employees)  
  
}  

在上面的程序中,原地图被分配给新地图,在下一行中,将新地图中的4=jack改为4=herald。这反映在原始地图中,输出被复制。

original map:  map[1:ram 2:arun 3:Gef 4:jack]  
new  map:  map[2:arun 3:Gef 4:herald 1:ram]  

地图复制的价值

在golang中,当地图被分配或传递给函数时,它是一个引用的副本,而不是存储的下划线数据。

我们如何复制地图数据?

下面的程序将地图数据复制到另一个地图上

  
package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map using map literal  
 source := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
 destination := make(map[int]string)  
 fmt.Println("source: ", source)  
 for key, value := range source {  
  destination[key] = value  
 }  
 fmt.Println("destination: ", destination)  
}  

上述程序的输出是

  
source:  map[2:arun 3:Gef 1:ram]  
destination:  map[1:ram 2:arun 3:Gef]  

检查地图的比较等价性

\== 用来检查地图值是否为空值。它对地图的平等性没有用处。为了比较两张地图是否相等,我们将写一段代码或使用reflect.DeepEqual()函数 reflect.DeepEqual()函数检查大小和每个项目是否相等。

package main  
  
import (  
 "fmt"  
 "reflect"  
)  
  
func main() {  
 // Create a map using map literal  
 source := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
 destination := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
 fmt.Println("source: ", source)  
 fmt.Println("destination: ", destination)  
 eq := reflect.DeepEqual(source, destination)  
 if eq {  
  fmt.Println("Maps are equal.")  
 } else {  
  fmt.Println("Maps are not unequal.")  
 }  
  
}  

输出是

source:  map[2:arun 3:Gef 1:ram]  
destination:  map[1:ram1 2:arun 3:Gef]  
Maps are not unequal.  

如何将地图的键/值转换为分片的例子?

下面的示例代码为地图的键和值创建了一个片断。
使用范围形式的for循环对地图进行迭代。每次迭代,键或值都被添加到相应的片断中。

package main  
  
import (  
 "fmt"  
)  
  
func main() {  
 // Create a map using map literal  
 mymap := map[int]string{  
  1: "ram",  
  2: "arun",  
  3: "Gef",  
 }  
 // convert map keys into slice  
 keySlice := make([]int, 0, len(mymap))  
 for k := range mymap {  
  keySlice = append(keySlice, k)  
 }  
 fmt.Println(keySlice)  
 // convert map values into slice  
 valueSlice := make([]string, 0, len(mymap))  
 for _, value := range mymap {  
  valueSlice = append(valueSlice, value)  
 }  
 fmt.Println(valueSlice)  
}  

上述程序的输出是

[2 3 1]  
[ram arun Gef]