Rumah > Artikel > pembangunan bahagian belakang > Peta dalam Go
Go menggabungkan jenis asli yang melaksanakan jadual cincang yang dipanggil peta. Ia ialah jenis data yang terdiri daripada koleksi kunci unik dan koleksi nilai untuk setiap kunci tersebut.
Ia boleh dibandingkan dengan kamus dalam bahasa lain, contohnya, yang menyimpan pasangan nilai kunci. Nilai ini diakses menggunakan kekunci, dengan cara yang sama seperti tatasusunan dan kepingan seperti yang kita lihat dalam siaran sebelumnya.
Indeks tidak terhad kepada nombor seperti dalam tatasusunan atau kepingan dan unsur-unsur tidak disusun, jadi jika kita mencetak peta, ia akan mengembalikan susunan rawak, jika kita tidak melakukan apa-apa untuk mengatasi pencetakannya dan memaksa susunan yang diingini.
Untuk mengisytiharkan peta, ia dilakukan dengan nilai map[key], di mana kunci akan menjadi jenis yang kita inginkan kunci kita (ia mestilah daripada jenis yang setanding https://go.dev/ref/spec#Comparison_operators ) dan nilai akan menjadi jenis yang kita mahu peta disimpan dalam setiap kekunci, apa sahaja jenisnya, daripada int kepada struct, atau peta lain, apa sahaja yang kita mahu.
Seperti hirisan, peta ialah jenis yang dirujuk, yang bermaksud nilai sifar peta adalah sifar.
Ini berlaku kerana di bawahnya terdapat jadual cincang yang menyimpan kunci dan nilai, dan ia hanyalah sampul surat, abstraksi, daripadanya.
Jika kami mengisytiharkannya sebagai:
var m map[int]int
nilainya akan menjadi sifar.
Jika kita mahu ia mempunyai nilai sifar, kita boleh menggunakan pengisytiharan:
m := map[int]int{}
Dan kita juga boleh memulakannya sama seperti kepingan, menggunakan fungsi make.
m := make(map[string]string)
Melakukan ini akan memulakan peta cincang dengan kumpulan memori yang sesuai untuknya, sekali gus mengembalikan peta yang menghala ke struktur data tersebut.
Menambah nilai pada peta dilakukan dengan menggunakan pendakap kerinting [] dan pendakap kerinting, sama seperti dengan tatasusunan atau kepingan. Dalam contoh ini, kami akan mencipta peta dengan kunci sebagai rentetan dan nilai sebagai integer, untuk menyimpan nama dan umur.
ages := make(map[string]int) ages["John"] = 33 ages["Charly"] = 27 ages["Jenny"] = 45 ages["Lisa"] = 19
Jika kami ingin menambah nilai padanya apabila kami mengisytiharkan peta, kami boleh menggunakan pengisytiharan pendek dan melakukan semuanya dalam langkah yang sama:
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19}
Untuk membaca nilai, kita hanya perlu menunjukkan kunci pada peta kita dan ia akan mengembalikan nilai tersebut. Contohnya, untuk mengetahui umur Lisa, kita boleh lakukan:
fmt.Println(ages["Lisa"]) // 19
Jika kita cuba mengakses kunci yang tidak wujud, nilai yang diperoleh ialah nilai sifar jenis, dalam kes ini ia akan menjadi "", kerana ia adalah rentetan.
Untuk menyemak sama ada unsur wujud dalam peta, kita boleh menyemak sama ada jenis itu adalah lalai, tetapi ia tidak begitu dipercayai, kerana mungkin ia wujud tetapi nilainya adalah rentetan kosong atau 0 dalam kes int , yang sepadan dengan nilai sifarnya, jadi Go membantu kami dengan perkara berikut:
val, ok := ages["Randy"]
Jika kita menyamakan peta dengan dua nilai, yang pertama ialah nilai elemen yang diakses melalui kekunci, dalam kes ini "Randy" yang tidak wujud dan yang kedua ialah boolean, yang akan menunjukkan sama ada ia wujud atau tidak.
Jika kami tidak berminat dengan nilai dan hanya ingin menyemak kewujudan kunci, kami boleh menggunakan _ untuk mengabaikan nilai seperti berikut:
_, ok := ages["Randy"]
Seperti tatasusunan dan kepingan, kita boleh menggunakan fungsi len untuk mengetahui berapa banyak elemen yang terdapat dalam peta.
fmt.Println(len(ages)) // 4
Jika kita ingin mengubah suai nilai, ia semudah mengakses nilai tersebut menggunakan kunci dan memadankannya dengan yang lain, dan ia akan diubah suai.
Jika kami mengisytiharkan peta kedua yang menunjuk kepada yang pertama, jika kami mengubah suai nilai yang kedua, kerana ia adalah jenis yang dirujuk, kami akan mengubah suai nilai yang pertama, kerana kedua-duanya berkongsi jadual cincang yang sama di bawahnya.
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19} agesNew := ages agesNew["Bryan"] = 77 fmt.Println(agesNew) // map[Bryan:77 Charly:27 Jenny:45 John:33 Lisa:19] fmt.Println(ages) // map[Bryan:77 Charly:27 Jenny:45 John:33 Lisa:19]
Untuk memadamkan elemen daripada peta, Go memberikan kami fungsi padam dengan tandatangan padam berikut(m map[Type]Type1, Key Type) yang menerima peta dan kunci untuk dipadamkan.
Dalam kes sebelumnya, jika kami ingin menghapuskan "Lisa" kami akan melakukannya:
delete(ages, "Lisa")
Jika kita ingin meneliti kandungan peta, kita boleh melakukannya menggunakan for dengan variasi julat yang telah kita lihat dalam siaran pada tatasusunan dan kepingan.
Pada masa itu, elemen pertama akan menjadi indeks, oleh itu kunci, dan yang kedua nilainya.
for key, value := range ages { fmt.Printf("%s: %d\n", key, value) } // Output: // Jenny: 45 // Lisa: 19 // John: 33 // Charly: 27
Seperti tatasusunan dan kepingan, jika kita hanya berminat dengan nilai, tanpa kunci, kita boleh meninggalkannya dengan menggunakan _.
for _, value := range ages { fmt.Println(value) } // Output: // 19 // 33 // 27 // 45
Dan jika perkara yang menarik minat kami hanyalah kuncinya, kami boleh menetapkan julat kepada pembolehubah tunggal untuk mendapatkannya:
for key := range ages { fmt.Println(key) } // Output: // John // Charly // Jenny // Lisa
As I mentioned in the introduction, in a map the information is not ordered, so when looping through it we cannot specify what order it follows, nor can Go guarantee that the order between executions is the same.
As we saw with arrays and slices, in the standard library there is a sort package which helps us sort elements: https://pkg.go.dev/sort
Following our example with ages and using sort, we can sort the keys of the map before traversing it and thus guarantee that it will be accessed in order.
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19} keys := make([]string, 0, len(ages)) for k := range ages { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { fmt.Println(k, ages[k]) } // Output: // Charly 27 // Jenny 45 // John 33 // Lisa 19
We declare our ages map with the short declaration as we saw before.
We create a string slices to store the keys and use the make method with 0 length, since we do not have any keys at the moment, but we do reserve the capacity it will have using the len method for the length of our map.
We go through the ages map to keep its keys and add them to the created slice.
We sort the keys alphabetically with the sort.Strings function.
We go through the slice of keys, already ordered, and access the map with the key in question.
This way we will access the map in an orderly manner and we can do the logic that our program needs.
Something to keep in mind with maps is that they are not safe to use concurrently. If these are concurrent reads, either accessing a value or through a for with a range, there is no problem with multiple goroutines accessing it at the same time.
The problematic case is when you want to update the value of a map concurrently, either by adding or removing elements from it, and at the same time you are reading it from another side, for example.
To solve this situation there are several possible solutions, which I will not go into much detail, I will simply mention and leave it to your choice to delve deeper into them.
If we use the sync package: https://pkg.go.dev/sync from the standard library, we can control the synchrony between the different goroutines.
A possible use is the RWMutex type which allows us to lock and unlock reads and writes to a type. So if we have a type that contains a sync.RWMutex and a map we can control when it can be accessed.
Another interesting type to investigate within the same sync package is Map, which already offers us a series of functions that will help us work with our map, which in the end we will not be able to work with natively, as with the previous solution.
Depending on the use case we are implementing, one or the other will be more useful to us, and there is no one better than the other, it will always depend on what we need.
I hope everything that I have tried to explain in this post has been clear, and please if there is any part that has not been completely clear or there are parts that I have not covered that you would like me to do, leave me a comment right here or through my social networks that you have on my profile and I will be happy to respond.
Atas ialah kandungan terperinci Peta dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!