The dictionary word for mathematics is mapping, the association of all elements in one set to some or all elements in another set, and only one-to-one or many-to-one mapping.

Array slicing gives us the ability to manipulate a contiguous chunk of memory, which is a unified management of homogeneous elements. The dictionary, on the other hand, gives relevance to discontinuous and different types of memory variables. It expresses a causal relationship. The key of the dictionary is the cause and the value of the dictionary is the effect. If arrays and slicing gave us the ability to walk, dictionaries gave us the ability to jump.

Pointers, array slices, and dictionaries are all container variables. Dictionaries are much simpler to use than array slices, but their internal structure is incredibly complex. In this section we will focus only on the basic use of the dictionary and will examine its internal structure in later advanced chapters.

Dictionary creation

There are many criticisms of the Go language, such as that it does not support generics. In fact, strictly speaking, Go supports generics, but very weakly, and generics are a very weak presence in the Go language. Array slicing and dictionary types, for example, support generics. When creating a dictionary, you must specify types for keys and values. Dictionaries can also be created using the make function

package main

import "fmt"

func main() {
	var m map[int]string = make(map[int]string)
	fmt.Println(m, len(m))
}

----------
map[] 0
Copy the code

The dictionary created using the make function is empty with zero length and no internal elements. If you need to provide initialized elements to the dictionary, you need to use a different way to create the dictionary.

package main

import "fmt"

func main() {
	var m map[int]string = map[int]string{
		90: "Good",
		80: "Good",
		60: "Pass", / / pay attention to the comma here are indispensable, otherwise it will quote syntax error} FMT. Println (m, len (m))} -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the map [90: outstanding 80: good 60: pass] 3Copy the code

Dictionary variables also support type derivation, and the above variable definition can be abbreviated as

var m = map[int]string{
 90: "Good",
 80: "Good",
 60: "Pass",}Copy the code

If you can predict the number of key-value pairs inside the dictionary, you can also pass an integer value to make to tell the runtime to allocate memory ahead of time. This eliminates the need for multiple expansion operations as dictionaries grow.

var m = make(map[int]string, 16)
Copy the code

Dictionary reading and writing

As in Python, dictionaries can read and write internal elements using brackets and delete elements using the delete function.

package main

import "fmt"

func main() {
	var fruits = map[string]int {
		"apple": 2."banana": 5,
		"orange"} var score = fruits["banana"Println(score) // Add or modify element fruits["pear"] = 3 FMT.Println(fruits) // delete(fruits,"pear")
	fmt.Println(fruits)
}

-----------------------
5
map[apple:2 banana:5 orange:8 pear:3]
map[orange:8 apple:2 banana:5]

Copy the code

What if the dictionary key doesn’t exist?

If the corresponding key does not exist during the delete operation, the delete function silently processes it. Unfortunately, the delete function does not return a value, so you can’t tell directly whether the delete operation actually deleted an element. You can find out by either reading the length or trying to read the value of the key beforehand.

If the key does not exist during the read operation, no exception is thrown. It returns zero for the value type. The zero value is empty if it is a string, zero if it is an integer, and false if it is a Boolean.

You can’t tell if the key exists by returning a zero value, because the value of the key might be zero, like in the dictionary below you can’t tell if “durin” exists

var m = map[string]int {
  "durin": 0 // Just chestnuts. Actually I prefer durian.Copy the code

The dictionary’s special syntax must be used, as follows

package main

import "fmt"

func main() {
	var fruits = map[string]int {
		"apple": 2."banana": 5,
		"orange": 8,
	}

	var score, ok = fruits["durin"]
	if ok {
		fmt.Println(score)
	} else {
		fmt.Println("durin not exists")
	}

	fruits["durin"] = 0
	score, ok = fruits["durin"]
	if ok {
		fmt.Println(score)
	} else {
		fmt.Println("durin still not exists")
	}
}

-------------
durin not exists
0
Copy the code

A subscript read of a dictionary can return two values, both of which indicate the existence of the corresponding key. This strange usage takes time for beginners to digest, and the reader doesn’t need to think too much about it. It’s just grammatical sugar provided by Go, and there’s not much mystery inside. A normal function call can return multiple values, but it does not have the special ability to “improvise” — “polymorphic return values.”

Dictionary traversal

Dictionary traversal provides the following two methods: one is to carry the value, the other is to only need the key, which needs to use the Go language range keyword.

package main

import "fmt"

func main() {
	var fruits = map[string]int {
		"apple": 2."banana": 5,
		"orange": 8,}for name, score := range fruits {
		fmt.Println(name, score)
	}

	for name := range fruits {
		fmt.Println(name)
	}
}

------------
orange 8
apple 2
banana 5
apple
banana
orange
Copy the code

Oddly, the Go dictionary doesn’t provide methods like keys() and values(), meaning that if you want to get a list of keys, you’ll have to loop through it yourself, as follows

package main

import "fmt"

func main() {
	var fruits = map[string]int {
		"apple": 2."banana": 5,
		"orange": 8,
	}

	var names = make([]string, 0, len(fruits))
	var scores = make([]int, 0, len(fruits))

	for name, score := range fruits {
		names = append(names, name)
		scores = append(scores, score)
	}

	fmt.Println(names, scores)
}

----------
[apple banana orange] [2 5 8]
Copy the code

This will make the code a bit cumbersome, but Go is not officially available, so get used to it

Thread (coroutine) safety

Go’s built-in dictionary is not thread-safe and must be controlled using locks if thread-safe is required. We will implement a thread-safe dictionary ourselves in the next section on locking.

What is stored in a dictionary variable?

The dictionary variable holds only an address pointer to the head object of the dictionary. So the space taken up by dictionary variables is one word, that is, the size of a pointer, 8 bytes for 64-bit machines and 4 bytes for 32-bit machines.

You can use the Sizeof function provided by the unsafe package to calculate the Sizeof a variable

package main

import (
	"fmt"
	"unsafe"
)

func main() {
	var m = map[string]int{
		"apple": 2."pear": 3."banana": 5,
	}
	fmt.Println(unsafe.Sizeof(m))
}

------
8
Copy the code

To consider

In the case of traversing the dictionary to get keys and values, we allocated the names and scores slices. What would happen if we adjusted the code snippet like this?

var names = make([]string, len(fruits))
var scores = make([]int, len(fruits))
Copy the code

Scan the QR code to read more chapters in Learn Go