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)
نمیتوان برای تعریف «کلید» مپ استفاده کرد.
در مپ میتوان برای کلید از مقدار داخل یک متغیر بهره برد.
package main
import "fmt"
func main() {
myMap := make(map[int]string)
myKey := 13
myMap[myKey] = "thirteen"
fmt.Println(myMap) //map[13:thirteen]
fmt.Println(myMap[myKey]) //thirteen
}
- مقدار: حاوی دادهای است که کلید به آن اشاره میکند و برخلاف کلید، هیچ محدودیت برای انتخاب «نوع» آن وجود ندارد، بهعنوان نمونه میتوان از یک مپ دیگر برای مقدار استفاده کرد. (مپهای تودرتو )
map[string]map[int]string
1.10.3 ایجاد و مقداردهی اولیه #
مقدار پیشفرض برای یک مپ nil میباشد. برای مقداردهی مپ ها از روشهای زیر استفاده میشود:
- استفاده از کلمه کلیدی var
var sampleMap = map[keyType]valueType{keyName1:value1, keyName2:value2, ...}
var sampleMap map[keyType]valueType = map[keyType]valueType{}
- استفاده از علامت
=:
short variable declaration
sampleMap := map[keyType]valueType{keyName1:value1, keyName2:value2, ...}
- استفاده از تابع make
var sampleMap = make(map[keyType]valueType)
sampleMap := make(map[keyType]valueType)
1.10.4 مپ با مقدار nil #
درصورت تعریف اولیه مپ توسط دستور var sampleMap map[keyType]valueType
یک مپ با مقدار nil ساخته میشود که نمیتوان بدون مقداردهی اولیه، روی آن عملیات ارسال و دریافت داده انجام داد:
var sampleMap map[uint8]int
sampleMap[13] = 9999999
//panic: assignment to entry in nil map
برای مقداردهی یک مپ nil که به روش زیر ساخته اید:
var m map[string]string
از روشهای زیر میتوان بهره گرفت:
var m map[string]string = map[string]string{}
m := make(map[string]string)
m := map[string]string{}
1.10.5 توابع مربوط به مپ #
- تابع (len):
برای برگشت تعداد عناصر داخل مپ از
len
استفاده میشود:package main import "fmt" func main() { var sampleMap = map[string]bool{} var otherMap = make(map[string]uint) var nilMap map[bool]bool sampleMap["condition#1"] = true sampleMap["condition#2"] = false otherMap["foo"] = 1 fmt.Println(len(sampleMap)) //2 fmt.Println(len(otherMap)) //1 fmt.Println(len(nilMap)) //0 (len nil is zero) }
مقدار برگشتی برای تابع len روی مپ nil برابر صفر (۰) است.
1.10.6 عملیات CRUD روی مپ #
برای ایجاد مپ، اغلب از تابع make استفاده می شود:
package main
import "fmt"
func main() {
animals := make(map[int]string) // nil map of string-int pairs
animals[1] = "Gopher"
animals[2] = "owl"
animals[3] = "cheetah"
animals[4] = "eagle"
animals[5] = "lion"
fmt.Println(animals) //map[1:Gopher 2:owl 3:cheetah 4:eagle 5:lion]
}
جهت خواندن مقادیر مپ میتوان از الگوی زیر استفاده کرد:
mapName["keyName"]
مثال:
package main
import "fmt"
func main() {
animals := make(map[int]string) // nil map of string-int pairs
animals[1] = "Gopher"
animals[2] = "owl"
animals[3] = "cheetah"
animals[4] = "eagle"
animals[5] = "lion"
fmt.Println(animals[2]) //owl
}
برای بروزرسانی مقادیر مپ، از الگوی
mapName[keyName] = newValue
استفاده میشود.
مثال:
package main
import "fmt"
func main() {
animals := make(map[int]string) // nil map of string-int pairs
animals[1] = "Gopher"
animals[2] = "owl"
animals[3] = "cheetah"
animals[4] = "eagle"
animals[5] = "lion"
fmt.Println(animals[2]) //owl
animals[2] = "wolf"
fmt.Println(animals[2]) //wolf
}
جهت حذف مقادیر در مپ، از تابع delete
متعلق به پکیج builtin
استفاده میشود.
package main
import "fmt"
func main() {
animals := make(map[int]string) // nil map of string-int pairs
animals[1] = "Gopher"
animals[2] = "owl"
animals[3] = "cheetah"
animals[4] = "eagle"
animals[5] = "lion"
fmt.Println(animals) //map[1:Gopher 2:owl 3:cheetah 4:eagle 5:lion]
fmt.Println(len(animals)) //5
delete(animals, 4)
fmt.Println(animals) //map[1:Gopher 2:owl 3:cheetah 5:lion]
fmt.Println(len(animals)) //4
}
نکته: اگر کلید مورد استفاده در فانکشن
delete()
پیدا نشود، هیچ اتفاقی نخواهد افتاد. علت عدم بازگشت ارور در فانکشنdelete()
است// The delete built-in function deletes the element with the specified key // (m[key]) from the map. If m is nil or there is no such element, delete // is a no-op. func delete(m map[Type]Type1, key Type)
1.10.7 بررسی وجود کلید #
یکی از خدماتی که مپ ارائه میدهد، پاسخ به سوال وجود یک کلید خاص در مپ میباشد که بهعنوان راهکاری برای حل مسائل از آن استفاده میشود. مثال زیر را ببینید:
package main
import "fmt"
func main() {
var personData = map[string]string{"name": "frank", "family": "colleti", "dob": "1970-05-12"}
name, nameExist := personData["name"]
family, familyExist := personData["family"]
dob, dobExist := personData["dob"]
organization, organizationExist := personData["organization"]
fmt.Println(name, nameExist)
//frank true
fmt.Println(family, familyExist)
//colleti true
fmt.Println(dob, dobExist)
//1970-05-12 true
fmt.Println(organization, organizationExist)
// false
}
- این روش بیشتر به اسم
comma, ok
شناخته میشود و بسیاری از توابع چه در کتابخانه استاندارد و چه کتابخانههای عمومی در گولنگ، از این نوع نامگذاری برای برگشت دادن مقدار و ارور پشتیبانی میکنند. - در مثال بالا تمامی متغیرهایی که با
Exist
تمام میشوند برای برسی وجود و عدم وجود یک کلید درمپ
استفاده میشوند، به این صورت که اگر مقدار مشخص شده درمپ
وجود داشت مقدار برگشتی در این متغیرهاtrue
خواهد بود و در غیر این صورت مقدار برگشتیfalse
.
1.10.8 مپ، یک جدول، یک منبع #
وقتی یک مپ تعریف میشود، اگر مپ(های) دیگری از روی آن ساخته شود، دارای یک منبع (reference type)
برای ذخیره و دریافت اطلاعات خواهند بود. در مثال زیر، مپ editorMap
از مپ companyProfile
ایجاد و وقتی ویرایش میشود، مپ اصلی نیز، ویرایش میشود.
package main
import "fmt"
func main() {
var companyProfile = map[string]string{
"name": "companyName",
"address": "sampleAddress",
}
var editorMap = companyProfile // == editorMap := companyProfile
fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
//companyName sampleAddress
fmt.Println(editorMap["name"], "\t", editorMap["address"])
//companyName sampleAddress
editorMap["name"] = "new name"
editorMap["address"] = "new address"
//reference map also edited when editor map edit
fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
//new name new address
fmt.Println(editorMap["name"], "\t", editorMap["address"])
//new name new address
}
برای اینکه بتوانید مقادیر یک مپ را درون یک مپ دیگر کپی کنید، راه حل این است داخل آن مپ پیمایش کنید و مقادیرش را در مپ جدید قرار دهید.
package main
import "fmt"
func main() {
var companyProfile = map[string]string{
"name": "companyName",
"address": "sampleAddress",
}
var editorMap = map[string]string{}
for key, value := range companyProfile {
editorMap[key] = value
}
fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
fmt.Println(editorMap["name"], "\t", editorMap["address"])
editorMap["name"] = "new address"
editorMap["address"] = "new address"
fmt.Println(companyProfile["name"], "\t", companyProfile["address"])
fmt.Println(editorMap["name"], "\t", editorMap["address"])
}
1.10.9 پیمایش روی مپ #
یکی از اصلیترین اهداف ایجاد و نگهداری انواع تایپهای مربوط به مجموعه دادهها، امکان دسترسی به اجزای داده و انواع لوپ از ابزارهای آن است. با استفاده از for-range میتوان به اجزای یک داده از نوع کلید-مقدار دسترسی داشت
package main
import (
"fmt"
)
func main() {
animals := make(map[int][]string) // nil map of string-int pairs
animals[0] = []string{"Gopher", "running", "rodent"}
animals[1] = []string{"owl", "flying", "carnivorous"}
animals[2] = []string{"cheetah", "running", "carnivorous"}
animals[3] = []string{"eagle", "flying", "carnivorous"}
animals[4] = []string{"lion", "running", "carnivorous"}
for index, animal := range animals {
fmt.Printf("%v- %s is %s animal and can %s \n", index, animal[0], animal[2], animal[1])
}
}
به نحوه چیدمان خروجیها دقت کنید، درباره علت یکسان نبودن خروجیها در اجراهای متعدد تحقیق کنید تقلب کوچیک بهتون بدم :). مپ ها unordered هستن
.
1.10.10 تبدیل اطلاعات رشته − مپ − اسلایس #
نمونه کد زیر یک رشته را به مپ و یک مپ را به اسلایس تبدیل میکند.
package main
import (
"fmt"
)
func seriesStringToMap(inputs ...string) map[int]string {
result := make(map[int]string)
for index, input := range inputs {
result[index] = input
}
return result
}
func mapToSlice(inputs map[int]string) []string {
result := make([]string, len(inputs))
for index, input := range inputs {
result[index] = input
}
return result
}
func main() {
myAnimal := "Eagle Cheetah Owl Lion Gopher"
myMappedAnimal := seriesStringToMap(myAnimal)
fmt.Println(myMappedAnimal)
//map[0:Eagle Cheetah Owl Lion Gopher]
mySlicedAnimal := mapToSlice(myMappedAnimal)
fmt.Println(mySlicedAnimal)
//[Eagle Cheetah Owl Lion Gopher]
}
1.10.11 خودآزمون #
کد زیر را بررسی کنید و خروجی(های) آن را با ذهن خود پردازش کنید. سپس صحت آن(ها) را بررسی و درباره آن تحقیق کنید:
package main
import "fmt"
func main() {
var myMap map[string]int
fmt.Println(myMap)
var otherMap = map[string]int{}
fmt.Println(otherMap)
myMap["foo"] = 13
fmt.Println(myMap)
otherMap["bar"] = 99
fmt.Println(otherMap)
}