1.10.1 مقدمه #
- نقشه ، یک نوع ساختار داده است.
- نقشه ها جهت جمعآوری و نگهداری مجموعهای از دادهها استفاده میگردند.
- نقشه ، از نوع دادههای انجمنی (هش) بصورت «کلید-مقدار» است.
- نقشه ، مجموعهای از دادهها بصورت جفتهای مرتبنشده است.
1.10.2 تعریف #
یک مپ شبیه به فرمت زیر است:
map[KeyType]ValueType
کلمه کلیدی map
و بعد نوع کلید و در آخر هم نوع مقدار تعریف میشود.
کلید: برای اشاره به یک مقدار ذخیره شده، نیاز به یک نام داریم و این یعنی «کلید» آن مقدار.
- مقدار کلید در یک مپ، باید یکتا باشد.
- محدودیت: برای تعریف کلید، از انواع تایپهایی که قابل مقایسه
هستند، میتوان استفاده کرد:
- Boolean(s)
- Number(s)
- String(s)
- Array(s)
- Pointer(s)
- Struct(s)
- Interface(s) (تا زمانی که از مقادیر مقایسهپذیر استفاده میکند)
- از
Slice(s)
Map(s)
Function(s)
نمیتوان برای تعریف «کلید» مپ استفاده کرد.
در مپ میتوان برای کلید از مقدار داخل یک متغیر بهره برد.
مقدار: حاوی دادهای است که کلید به آن اشاره میکند و برخلاف کلید، هیچ محدودیت برای انتخاب «نوع» آن وجود ندارد، بهعنوان نمونه میتوان از یک مپ دیگر برای مقدار استفاده کرد. (مپهای تودرتو )
map[string]map[int]string
1.10.3 ایجاد و مقداردهی اولیه #
مقدار پیشفرض برای یک مپ nil میباشد. برای مقداردهی مپ ها از روشهای زیر استفاده میشود:
- استفاده از کلمه کلیدی var
1var sampleMap = map[keyType]valueType{keyName1:value1, keyName2:value2, ...}
2var sampleMap map[keyType]valueType = map[keyType]valueType{}
- استفاده از علامت
=:
short variable declaration
1sampleMap := map[keyType]valueType{keyName1:value1, keyName2:value2, ...}
- استفاده از تابع make
1.10.4 مپ با مقدار nil #
درصورت تعریف اولیه مپ توسط دستور var sampleMap map[keyType]valueType
یک مپ با مقدار nil ساخته میشود که نمیتوان بدون مقداردهی اولیه، روی آن عملیات ارسال و دریافت داده انجام داد:
برای مقداردهی یک مپ nil که به روش زیر ساخته اید:
1var m map[string]string
از روشهای زیر میتوان بهره گرفت:
1var m map[string]string = map[string]string{}
2m := make(map[string]string)
3m := map[string]string{}
1.10.5 توابع مربوط به مپ #
- تابع (len):
برای برگشت تعداد عناصر داخل مپ از
len
استفاده میشود:
1package main
2
3import "fmt"
4
5func main() {
6 var sampleMap = map[string]bool{}
7 var otherMap = make(map[string]uint)
8 var nilMap map[bool]bool
9
10 sampleMap["condition#1"] = true
11 sampleMap["condition#2"] = false
12
13 otherMap["foo"] = 1
14
15 fmt.Println(len(sampleMap)) //2
16 fmt.Println(len(otherMap)) //1
17 fmt.Println(len(nilMap)) //0 (len nil is zero)
18}
مقدار برگشتی برای تابع len روی مپ nil برابر صفر (۰) است.
1.10.6 عملیات CRUD روی مپ #
برای ایجاد مپ، اغلب از تابع make استفاده می شود:
1package main
2
3import "fmt"
4
5func main() {
6 animals := make(map[int]string) // nil map of string-int pairs
7 animals[1] = "Gopher"
8 animals[2] = "owl"
9 animals[3] = "cheetah"
10 animals[4] = "eagle"
11 animals[5] = "lion"
12
13 fmt.Println(animals) //map[1:Gopher 2:owl 3:cheetah 4:eagle 5:lion]
14
15}
جهت خواندن مقادیر مپ میتوان از الگوی زیر استفاده کرد:
mapName["keyName"]
مثال:
برای بروزرسانی مقادیر مپ، از الگوی
mapName[keyName] = newValue
استفاده میشود.
مثال:
1package main
2
3import "fmt"
4
5func main() {
6 animals := make(map[int]string) // nil map of string-int pairs
7 animals[1] = "Gopher"
8 animals[2] = "owl"
9 animals[3] = "cheetah"
10 animals[4] = "eagle"
11 animals[5] = "lion"
12
13 fmt.Println(animals[2]) //owl
14
15 animals[2] = "wolf"
16
17 fmt.Println(animals[2]) //wolf
18}
جهت حذف مقادیر در مپ، از تابع delete
متعلق به پکیج builtin
استفاده میشود.
1package main
2
3import "fmt"
4
5func main() {
6 animals := make(map[int]string) // nil map of string-int pairs
7 animals[1] = "Gopher"
8 animals[2] = "owl"
9 animals[3] = "cheetah"
10 animals[4] = "eagle"
11 animals[5] = "lion"
12
13 fmt.Println(animals) //map[1:Gopher 2:owl 3:cheetah 4:eagle 5:lion]
14 fmt.Println(len(animals)) //5
15 delete(animals, 4)
16
17 fmt.Println(animals) //map[1:Gopher 2:owl 3:cheetah 5:lion]
18 fmt.Println(len(animals)) //4
19}
نکته: اگر کلید مورد استفاده در فانکشن
delete()
پیدا نشود، هیچ اتفاقی نخواهد افتاد. علت عدم بازگشت ارور در فانکشنdelete()
است
1.10.7 بررسی وجود کلید #
یکی از خدماتی که مپ ارائه میدهد، پاسخ به سوال وجود یک کلید خاص در مپ میباشد که بهعنوان راهکاری برای حل مسائل از آن استفاده میشود. مثال زیر را ببینید:
1package main
2
3import "fmt"
4
5func main() {
6
7 var personData = map[string]string{"name": "frank", "family": "colleti", "dob": "1970-05-12"}
8
9 name, nameExist := personData["name"]
10 family, familyExist := personData["family"]
11 dob, dobExist := personData["dob"]
12 organization, organizationExist := personData["organization"]
13
14 fmt.Println(name, nameExist)
15 //frank true
16 fmt.Println(family, familyExist)
17 //colleti true
18 fmt.Println(dob, dobExist)
19 //1970-05-12 true
20 fmt.Println(organization, organizationExist)
21 // false
22}
- این روش بیشتر به اسم
comma, ok
شناخته میشود و بسیاری از توابع چه در کتابخانه استاندارد و چه کتابخانههای عمومی در گولنگ، از این نوع نامگذاری برای برگشت دادن مقدار و ارور پشتیبانی میکنند. - در مثال بالا تمامی متغیرهایی که با
Exist
تمام میشوند برای برسی وجود و عدم وجود یک کلید درمپ
استفاده میشوند، به این صورت که اگر مقدار مشخص شده درمپ
وجود داشت مقدار برگشتی در این متغیرهاtrue
خواهد بود و در غیر این صورت مقدار برگشتیfalse
.
1.10.8 مپ، یک جدول، یک منبع #
وقتی یک مپ تعریف میشود، اگر مپ(های) دیگری از روی آن ساخته شود، دارای یک منبع (reference type)
برای ذخیره و دریافت اطلاعات خواهند بود. در مثال زیر، مپ editorMap
از مپ companyProfile
ایجاد و وقتی ویرایش میشود، مپ اصلی نیز، ویرایش میشود.
1package main
2
3import "fmt"
4
5func main() {
6
7 var companyProfile = map[string]string{
8 "name": "companyName",
9 "address": "sampleAddress",
10 }
11 var editorMap = companyProfile // == editorMap := companyProfile
12
13 fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
14 //companyName sampleAddress
15 fmt.Println(editorMap["name"], "\t", editorMap["address"])
16 //companyName sampleAddress
17
18 editorMap["name"] = "new name"
19 editorMap["address"] = "new address"
20
21 //reference map also edited when editor map edit
22 fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
23 //new name new address
24 fmt.Println(editorMap["name"], "\t", editorMap["address"])
25 //new name new address
26}
برای اینکه بتوانید مقادیر یک مپ را درون یک مپ دیگر کپی کنید، راه حل این است داخل آن مپ پیمایش کنید و مقادیرش را در مپ جدید قرار دهید.
1package main
2
3import "fmt"
4
5func main() {
6 var companyProfile = map[string]string{
7 "name": "companyName",
8 "address": "sampleAddress",
9 }
10
11 var editorMap = map[string]string{}
12
13 for key, value := range companyProfile {
14 editorMap[key] = value
15 }
16
17 fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
18 fmt.Println(editorMap["name"], "\t", editorMap["address"])
19
20 editorMap["name"] = "new address"
21 editorMap["address"] = "new address"
22
23 fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
24 fmt.Println(editorMap["name"], "\t", editorMap["address"])
25}
1.10.9 پیمایش روی مپ #
یکی از اصلیترین اهداف ایجاد و نگهداری انواع تایپهای مربوط به مجموعه دادهها، امکان دسترسی به اجزای داده و انواع لوپ از ابزارهای آن است. با استفاده از for-range میتوان به اجزای یک داده از نوع کلید-مقدار دسترسی داشت
1package main
2
3import (
4 "fmt"
5)
6
7func main() {
8 animals := make(map[int][]string) // nil map of string-int pairs
9 animals[0] = []string{"Gopher", "running", "rodent"}
10 animals[1] = []string{"owl", "flying", "carnivorous"}
11 animals[2] = []string{"cheetah", "running", "carnivorous"}
12 animals[3] = []string{"eagle", "flying", "carnivorous"}
13 animals[4] = []string{"lion", "running", "carnivorous"}
14
15 for index, animal := range animals {
16 fmt.Printf("%v- %s is %s animal and can %s \n", index, animal[0], animal[2], animal[1])
17 }
18}
خروجی کد بالا:
1user@system:~/go/src/temp❇ GO[1.19.3] 22:29:00
2→ go run main.go
30- Gopher is rodent animal and can running
41- owl is carnivorous animal and can flying
52- cheetah is carnivorous animal and can running
63- eagle is carnivorous animal and can flying
74- lion is carnivorous animal and can running
8user@system:~/go/src/temp❇ GO[1.19.3] 22:29:00
9→ go run main.go
104- lion is carnivorous animal and can running
110- Gopher is rodent animal and can running
121- owl is carnivorous animal and can flying
132- cheetah is carnivorous animal and can running
143- eagle is carnivorous animal and can flying
15user@system:~/go/src/temp❇ GO[1.19.3] 22:29:02
16→ go run main.go
172- cheetah is carnivorous animal and can running
183- eagle is carnivorous animal and can flying
194- lion is carnivorous animal and can running
200- Gopher is rodent animal and can running
211- owl is carnivorous animal and can flying
به نحوه چیدمان خروجیها دقت کنید، درباره علت یکسان نبودن خروجیها در اجراهای متعدد تحقیق کنید تقلب کوچیک بهتون بدم :). مپ ها unordered هستن
.
1.10.10 تبدیل اطلاعات رشته − مپ − اسلایس #
نمونه کد زیر یک رشته را به مپ و یک مپ را به اسلایس تبدیل میکند.
1package main
2
3import (
4 "fmt"
5)
6
7func seriesStringToMap(inputs ...string) map[int]string {
8 result := make(map[int]string)
9 for index, input := range inputs {
10 result[index] = input
11 }
12 return result
13}
14
15func mapToSlice(inputs map[int]string) []string {
16 result := make([]string, len(inputs))
17 for index, input := range inputs {
18 result[index] = input
19 }
20 return result
21}
22
23func main() {
24 myAnimal := "Eagle Cheetah Owl Lion Gopher"
25
26 myMappedAnimal := seriesStringToMap(myAnimal)
27 fmt.Println(myMappedAnimal)
28 //map[0:Eagle Cheetah Owl Lion Gopher]
29
30 mySlicedAnimal := mapToSlice(myMappedAnimal)
31 fmt.Println(mySlicedAnimal)
32 //[Eagle Cheetah Owl Lion Gopher]
33}
1.10.11 خودآزمون #
کد زیر را بررسی کنید و خروجی(های) آن را با ذهن خود پردازش کنید. سپس صحت آن(ها) را بررسی و درباره آن تحقیق کنید: