Map集合
概述
Map 是一種無序的鍵值對的集合。
Map 最重要的一點是通過 key 來快速檢索數據,key 類似于索引,指向數據的值。
Map 是一種集合,所以我們可以像迭代數組和切片那樣迭代它。不過,Map 是無序的,遍歷 Map 時返回的鍵值對的順序是不確定的。
在獲取 Map 的值時,如果鍵不存在,返回該類型的零值,例如 int 類型的零值是 0,string 類型的零值是 “”。
Map 是引用類型,如果將一個 Map 傳遞給一個函數或賦值給另一個變量,它們都指向同一個底層數據結構,因此對 Map 的修改會影響到所有引用它的變量。
定義map
map關鍵字定義
基本語法
var 集合名 map[鍵類型]值類型;
舉例
package map_knowledgeimport "fmt"//通過關鍵字定義map
func CreateMap() {var map1 map[string]string;fmt.Printf("map1的值為%#v\n",map1)
}
結果
map1的值為map[string]string(nil)
注意
用關鍵字定義的map初始值為nil
,我們不能對其直接操作。
package map_knowledgeimport "fmt"//通過關鍵字定義map
func CreateMap() {var map1 map[string]string;fmt.Printf("map1的值為%#v\n",map1)//用關鍵字定義的map為nil,不能直接操作/*報錯:panic: assignment to entry in nil map*/// map1["name"] = "zhansan"
}
小結
這種用關鍵字定義的map就是一個空集合,如果要能夠操作只有兩種等價方案。
function CreateMap(){//方案1:定義完后用make開辟空間var map1 map[string]stringmap1 = make(map[string]string)//方案2:定義的時候賦值初始化//這樣golang也會為map開辟空間var map2 = map[string]string{"name":"lisa"}
}
make定義
make
既可以用于幫空集合開辟空間,也可以直接定義集合,golang官方也推薦這種形式。
基本語法
/* 使用 make 函數 */
map_variable := make(map[KeyType]ValueType, initialCapacity)
其中KeyType
是鍵的類型,ValueType
是值的類型,initialCapacity
是可選的參數,用于指定 Map 的初始容量。
Map 的容量是指 Map 中可以保存的鍵值對的數量,當 Map 中的鍵值對數量達到容量時,Map 會自動擴容。
如果不指定 initialCapacity,Go 語言會根據實際情況選擇一個合適的值。
一般來說我們不用特別指定容量,因為即使我們指定了,如果不夠也會自己擴容。
舉例
//通過make定義map
func CreateMapByMake(){var map1 = make(map[string]string,2)fmt.Printf("map1的值為%#v\n",map1)
}
結果
map1的值為map[string]string{}
注意
由于make定義開辟了空間,所以map可以直接操作。(這也是推薦用make定義的原因。)
func CreateMapByMake(){var map1 = make(map[string]string,2)fmt.Printf("map1的值為%#v\n",map1)map1["name"]="lisa"fmt.Printf("賦值后,map1的值為%#v\n",map1)
}
結果為
map1的值為map[string]string{}
賦值后,map1的值為map[string]string{"name":"lisa"}
map初始化
字面量初始化
基本語法
var map變量 map[鍵類型]值類型 = map[鍵類型]值類型{初始值}
//可以省略左邊的類型
var map變量 = map[鍵類型]值類型{初始值}
map可以通過賦值直接初始化,例如:
var map1 = map[string]int{//最后一項也要有逗號"name":10,
}
注意事項
以字面量初始化map
,內部的每一項用,
隔開,且最后一項也必須要有,
make初始化
我們先查看make
的源碼:
func make(t Type, size ...IntegerType) Type
所以make
只能先定義map,然后靠賦值初始化。
var map1 = make(map[string]int)
map1["age"] = 19
map訪問
注意事項
我們只能操作開辟了內存空間的map,用關鍵字定義但是沒有初始化的map是空map,無法操作.(見上文)
訪問map
基本語法
map[keyValue];
訪問不存在的鍵名不會報錯,只會返回值類型的零值。
因為
map[鍵類型]值類型
,起初就指定了值的類型
舉例
//訪問map
func VisitMap(){var map1 = map[string]int{"age":19,}fmt.Printf("age的值為%#v\n",map1["age"])fmt.Printf("訪問不存在的項值為%#v\n",map1["other"])
}
結果
age的值為19
訪問不存在的項值為0
嚴格訪問map
我們還可以用另一種方式訪問map
,來得知鍵是否存在。
基本語法
/*第一個返回值是鍵名對應的值,如果存在則返回值,否則為類型零值第二個返回值判斷鍵是否存在,如果存在則是true,反之false
*/
val,isOk := map[鍵名]
舉例
func VisitMapIsOk(){var map1 = map[string]int{"age":19,}ageVal,isAgeOk := map1["age"]fmt.Printf("age存在為%v,age的值為%#v\n",isAgeOk,ageVal)nameVal,isNameOk := map1["name"]fmt.Printf("name存在為%v,name的值為%#v\n",isNameOk,nameVal)
}
結果
age存在為true,age的值為19
name存在為false,name的值為0
任意類型的值
我們可以用interface{}
空接口類型來接收任意類型的值。
func InterfaceMap(){//interface{}是值類型var map1 = map[string]interface{}{"name":"lisa","age":19,}for key, val := range map1 {fmt.Printf("鍵%v對應的值為%v\n",key,val)}
}
結果
鍵name對應的值為lisa
鍵age對應的值為19
注意事項1:零值
interface{}
是一個字面量類型,被稱為空接口類型,零值為<nil>
func InterfaceMap(){var map1 = map[string]interface{}{"name":"lisa","age":19,}for key, val := range map1 {fmt.Printf("鍵%v對應的值為%v\n",key,val)}//注意事項1:interface{}是一個類型,零值為nilfmt.Printf("不存在的鍵的值為%v\n",map1["other"])
}
結果
鍵name對應的值為lisa
鍵age對應的值為19
不存在的鍵的值為<nil>
注意實現2:類型斷言
interface{}
類型的值在實際使用時需要類型斷言,
斷言語法
講接口時會詳述
var n interface{}
n = "world"
//val是值,ok代表是否成功
val,ok := n.(string)
如果斷言出錯也會報錯,例如
func InterfaceMap(){var map1 = map[string]interface{}{"name":"lisa","age":19,}for key, val := range map1 {fmt.Printf("鍵%v對應的值為%v\n",key,val)}//注意事項1:interface{}是一個類型,零值為nilfmt.Printf("不存在的鍵的值為%v\n",map1["other"])//注意事項2:interface{}類型的值在實際使用時要進行類型斷言if(map1["age"].(int64)>=18){fmt.Printf("你已經是個成年人了")}
}
報錯
panic: interface conversion: interface {} is int, not int64
正確案例
func InterfaceMap(){var map1 = map[string]interface{}{"name":"lisa","age":19,}for key, val := range map1 {fmt.Printf("鍵%v對應的值為%v\n",key,val)}//注意事項1:interface{}是一個類型,零值為nilfmt.Printf("不存在的鍵的值為%v\n",map1["other"])//注意事項2:interface{}類型的值在實際使用時要進行類型斷言/*可以先通過打印來判斷具體類型,或者用switch方法*/fmt.Printf("鍵age的值類型為%T\n",map1["age"])if(map1["age"].(int)>=18){fmt.Printf("你已經是個成年人了")}
}
結果
鍵name對應的值為lisa
鍵age對應的值為19
不存在的鍵的值為<nil>
鍵age的值類型為int
你已經是個成年人了
map增改
基本語法
map[鍵] = 值
如果鍵存在就是修改,否則就是新增。
map的長度
基本語法
len(map)
注意:不能用
cap(map)
求容量,因為map
的容量用處不大,只是初始開辟空間時給個提示,未來可以輕松擴容。
舉例
func GetMapLen(){var map1 = map[string]int{"age":19,}fmt.Printf("map1的長度為%d\n",len(map1))
}
結果
map1的長度為1
delete刪除元素
基本語法
//要注意鍵的類型,golang是強類型語言
delete(map變量,鍵名)
舉例
func DelMapItem(){var map1 = map[int64]string{1:"hello",2:"world",}fmt.Printf("刪除前map1的值為%#v\n",map1)//刪除delete(map1,1)fmt.Printf("刪除后map1的值為%#v\n",map1)
}
結果
刪除前map1的值為map[int64]string{1:"hello", 2:"world"}
刪除后map1的值為map[int64]string{2:"world"}
注意事項
1.刪除不存在的鍵不會報錯。例如
func DelMapItem(){var map1 = map[int64]string{1:"hello",2:"world",}fmt.Printf("刪除前map1的值為%#v\n",map1)//刪除delete(map1,1)fmt.Printf("刪除后map1的值為%#v\n",map1)//刪除不存在的鍵,不會報錯delete(map1,3)
}
2.被刪除元素的影響
如果是map存在的元素:
1.map長度發生變化
2.map遍歷時訪問不到
但是我們仍然可以通過map[鍵名]
訪問到,返回值類型的零值,和之前一樣。
但是用嚴格訪問會提示為false
.
map遍歷
我們可以用for...range
遍歷map。
基本語法
for 鍵,值 := range map{}
舉例
//遍歷map
func RnageMap(){var map1 = map[int64]string{1:"hello",2:"world",}for key, val := range map1 {fmt.Printf("鍵%v對應的值為%v\n",key,val)}
}
結果
鍵1對應的值為hello
鍵2對應的值為world