Go에는 맵이라는 해시 테이블을 구현하는 기본 유형이 통합되어 있습니다. 고유 키 모음과 각 키에 대한 값 모음으로 구성된 데이터 유형입니다.
예를 들어 키-값 쌍을 저장하는 다른 언어의 사전과 비교할 수 있습니다. 이러한 값은 이전 게시물에서 본 배열 및 슬라이스와 동일한 방식으로 키를 사용하여 액세스됩니다.
인덱스는 배열이나 슬라이스처럼 숫자로 제한되지 않으며 요소는 순서가 지정되어 있지 않습니다. 따라서 맵을 인쇄하면 인쇄를 재정의하고 원하는 순서를 강제로 적용하기 위해 아무 조치도 취하지 않으면 임의의 순서가 반환됩니다.
맵을 선언하려면 map[key]값을 사용하면 됩니다. 여기서 key는 우리가 원하는 키 유형입니다(비교 가능한 유형이어야 합니다 https://go.dev/ref/spec#Comparison_operators). ) 그리고 값은 int에서 구조체까지, 또는 다른 맵 등 우리가 원하는 모든 유형에 관계없이 맵이 각 키에 저장되기를 원하는 유형이 될 것입니다.
슬라이스와 마찬가지로 맵은 참조 유형이므로 맵의 0 값은 nil이 됩니다.
이는 그 아래에 키와 값을 저장하는 해시 테이블이 있고 그것들은 단순히 그것들의 추상화인 봉투이기 때문에 발생합니다.
다음과 같이 선언하면:
var m map[int]int
값은 0이 됩니다.
0 값을 원할 경우 다음 선언을 사용할 수 있습니다.
m := map[int]int{}
make 함수를 사용하면 슬라이스처럼 초기화할 수도 있습니다.
m := make(map[string]string)
이렇게 하면 적절한 메모리 풀로 해시 맵이 초기화되어 해당 데이터 구조를 가리키는 맵이 반환됩니다.
맵에 값을 추가하려면 배열이나 슬라이스와 마찬가지로 중괄호 []와 중괄호를 사용하면 됩니다. 이 예에서는 이름과 나이를 저장하기 위해 키가 문자열이고 값이 정수인 맵을 생성합니다.
ages := make(map[string]int) ages["John"] = 33 ages["Charly"] = 27 ages["Jenny"] = 45 ages["Lisa"] = 19
맵을 선언할 때 여기에 값을 추가하려면 짧은 선언을 사용하고 모든 작업을 동일한 단계에서 수행할 수 있습니다.
ages := map[string]int{"John": 33, "Charly": 27, "Jenny": 45, "Lisa": 19}
값을 읽으려면 지도에 키를 표시하기만 하면 해당 값이 반환됩니다. 예를 들어 Lisa의 나이를 알아내려면 다음을 수행할 수 있습니다.
fmt.Println(ages["Lisa"]) // 19
존재하지 않는 키에 액세스하려고 하면 얻은 값은 해당 유형의 0 값이 됩니다. 이 경우 문자열이므로 ""가 됩니다.
맵에 요소가 존재하는지 확인하기 위해 유형이 기본값인지 확인할 수 있지만 신뢰도가 높지는 않습니다. 요소가 존재하지만 해당 값이 빈 문자열이거나 int의 경우 0이기 때문입니다. , 이는 0 값과 일치하므로 Go는 다음을 수행하는 데 도움이 됩니다.
val, ok := ages["Randy"]
맵을 두 값과 동일하게 하면 첫 번째 값은 키를 통해 액세스된 해당 요소의 값(이 경우 존재하지 않는 "Randy")이고 두 번째 값은 부울 값이 됩니다. 존재하는지 존재하지 않는지.
값에 관심이 없고 단순히 키의 존재만 확인하려는 경우 다음과 같이 _를 사용하여 값을 무시할 수 있습니다.
_, ok := ages["Randy"]
배열 및 슬라이스와 마찬가지로 len 함수를 사용하여 맵에 요소가 몇 개 있는지 확인할 수 있습니다.
fmt.Println(len(ages)) // 4
값을 수정하려면 키를 사용하여 해당 값에 액세스하고 다른 값과 일치시키면 수정되기만 하면 됩니다.
첫 번째 맵을 가리키는 두 번째 맵을 선언하고 두 번째 맵의 값을 수정하면 참조 유형이므로 첫 번째 맵의 값을 수정하게 됩니다. 두 맵 모두 아래에서 동일한 해시 테이블을 공유하기 때문입니다.
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]
맵에서 요소를 삭제하기 위해 Go는 삭제될 맵과 키를 받는 다음 시그니처 delete(m map[Type]Type1, key Type)를 사용하여 삭제 함수를 제공합니다.
이전 사례에서 "Lisa"를 제거하려면 다음과 같이 하십시오.
delete(ages, "Lisa")
맵의 내용을 살펴보고 싶다면 배열과 슬라이스에 대한 게시물에서 이미 본 범위의 변형과 함께 for를 사용하면 됩니다.
그러면 첫 번째 요소는 인덱스(즉, 키)가 되고 두 번째 요소는 값이 됩니다.
for key, value := range ages { fmt.Printf("%s: %d\n", key, value) } // Output: // Jenny: 45 // Lisa: 19 // John: 33 // Charly: 27
배열 및 슬라이스와 마찬가지로 값에만 관심이 있고 키가 없으면 _를 사용하여 생략할 수 있습니다.
for _, value := range ages { fmt.Println(value) } // Output: // 19 // 33 // 27 // 45
그리고 우리가 관심을 갖는 것이 단순히 키라면 범위를 단일 변수에 할당하여 키를 얻을 수 있습니다.
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.
위 내용은 Go의 지도의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!