GO學習筆記——map(13)

每個語言基本都有類似於map的容器,C++有map和unordered_map,map的底層是紅黑樹,unordered_map的底層是哈希表。那麼GO語言中的map它的底層就是哈希表了。下面來討論GO語言中的map的使用


定義map

可以用下面的方式直接定義

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}

	fmt.Println(m1)
}

其中定義的第一行,map表示變量m是一個map,[string]表示它的key是一個string,後面跟着的string表示它的值是一個string,花括號{}內部是給這個map添加的一些元素

另外也可以用make來定義

m2 := make(map[string]string)

上面創建了一個空的map,注意空的map和nil的區別

func main() {
	m2 := make(map[string]string)	//空map
	var m3 map[string]string	//nil

        m2["April"] = "4"	//添加成功
	m3["April"] = "4"	//運行時出錯

	fmt.Println(m2)
	fmt.Println(m3)
}

用make創建出來的是一個空map,而如果像下面一行那樣只是用var來聲明,那麼其實這個m3是一個nil,nil是map的默認零值,這個和Slice一樣,往nil的map中插入數據會出錯

panic: assignment to entry in nil map

所以不推薦使用var來只聲明而不定義一個map,聲明瞭還是需要用make來給map定義。

向map中添加元素

添加元素有點像C++的map重載的[]的方法,直接使用[]來像map中添加和修改元素,用過C++的map的應該很好理解

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}

	fmt.Println(m1)
	m1["April"] = "4"	//添加成功
	fmt.Println(m1)
	m1["January"] = "一月"
	fmt.Println(m1)		//修改成功
}

輸出結果

map[January:1 February:2 March:3]
map[January:1 February:2 March:3 April:4]
map[January:一月 February:2 March:3 April:4]    //修改成功

遍歷map

range也可以用在對map的遍歷,事實上許多容器都可以用range來遍歷

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}
    
        m1["April"] = "4"	//添加成功
	for k,v := range m1 {
		fmt.Println(k,v)
	}
}

輸出結果

January 1
February 2
March 3
April 4

range同樣返回兩個值,第一個表示map的key,第二個表示map的value,和數組的使用方式一樣,如果我們只想要value,那麼需要k的位置需要用下劃線_代替。

至於爲什麼輸出的結果順序爲什麼不是有序的,即如果是有序的,那麼輸出的結果是按key的大小排序的(即April,February,March,Month),這裏學過C++的應該瞭解過map和unordered_map的區別,map的底層是紅黑樹,遍歷一棵紅黑樹的時候,我們遍歷的時候是按大小比較遍歷的,而GO的map相當於unordered_map,底層是哈希表實現的,哈希表不能保證插入進來的元素的有序性,它是無序的,但是它的插入效率要比紅黑樹快一點,因此就是犧牲有序性來提升效率。

 

獲取map中的元素

獲取元素同樣通過[]來獲取,只不過注意一下它的返回值。

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}


	month := m1["January"]
	fmt.Println(month)
}

這邊通過[]獲取到了key爲January的value,那麼這個時候如果想要獲取一個不存在的key的value會怎麼樣呢?

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}


	month := m1["April"]
	fmt.Println(month)
	fmt.Println(m1)
}

輸出結果


map[March:3 January:1 February:2]

輸出了一個空串,所以如果key不存在,那麼返回的是value的默認零值。我們之後也打印了一下m1,發現m1中並沒有這個April。其實學過C++的在這裏地方會有一點問題,因爲在這種情況下,C++的map中是會將April這個key插入到map中的。

來看一下下面的C++代碼

#include <iostream>
#include <map>
using namespace std;

int main(){
    map<string,string> m1;
    m1["January"] = "1";
    m1["February"] = "2";
    m1["March"] = "3";

    for(auto i : m1)
        cout << i.first << ":" << i.second << endl;

    cout << endl;
    string month = m1["April"];
    for(auto i : m1)
        cout << i.first << ":" << i.second << endl;
    return 0;
}

輸出結果

February:2
January:1
March:3

April:
February:2
January:1
March:3

可見,GO語言在這個地方和C++就不同了,需要注意,GO只有在真正地執行添加元素的操作纔會往map中添加元素,而C++只要使用到對應的key就會往map中添加這個key

另外,如果想要判斷key在map中是否存在怎麼做呢?GO通過下面的方式來解決

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}

	month,ok:= m1["April"]
	fmt.Println(month,ok)
	month,ok = m1["January"]
	fmt.Println(month,ok)
}

輸出結果

 false
1 true

其實調用[]返回的是兩個值,第一個是key對應的value,第二個返回值表示這個key是否存在,是一個bool類型。所以,如果我們只想判斷這個key是否存在,就可以用下劃線_代替前面的value不接收那個參數

 

刪除map中的元素

刪除map中的元素使用內置函數delete

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}

	month,ok := m1["January"]
	fmt.Println(month,ok)

	delete(m1,"January")

	month,ok = m1["January"]
	fmt.Println(month,ok)
}

輸出結果

1 true
 false

這樣就把key爲January的元素刪除了

 

獲取map中元素的個數

獲取元素個數使用len內置函數

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}

	fmt.Println(len(m1))
}

輸出結果

3

 

map是引用類型

func change(m1 map[string]string){
	m1["January"] = "一月"
}

func main() {
	m1 := map[string]string{
		"January" : "1",
		"February" : "2",
		"March" : "3",
	}

	change(m1)
	fmt.Println(m1)
}

輸出結果

map[January:一月 February:2 March:3]

因爲map是引用類型,所以它作爲參數傳給函數參數的時候,是引用傳遞,因此在函數內部對map的改變也會影響到原有的map。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章