在本教程中,我们将通过实例学习Go语言中的地图内置类型。
Go语言地图教程
map 是一种流行的集合数据结构,包含key 和value 对。 在其他编程语言中,它被用来表示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]