前期回顧
在上面的文章中,老貓和大家分享了GO語言中比較重要的兩種數據結構,一種是數組,另外一種是基於數組的slice。本篇文章想要繼續和大家分享剩下的容器以及字符字符串的處理。
MAP
map的定義
在Java語言中其實還有一個鍵值對的容器,叫做Map,當然在我們GO語言中也有這種數據結構,例如,下面咱們就來看一下GO語言中Map的寫法以及用法。看下一Map的語法定義,如下例子:
m :=map[string]string {
"name":"ktdaddy",
"age":"28",
"job":"softEngineer",
}
關於語法的定義其實也是比較簡單的,方括號里面的表示key值,后面的那個類型表示value的類型。上面老貓其實定義了一個map,並且給它初始化了一些數據。定義一個空的map其實也是比較簡單的,主要有下面兩種方式
m1 :=make(map[string]int) //采用make函數直接創建一個map,比較常用
var m2 map[string] int //用var函數申明的方式創建map
說實在的語法這種東西也沒法說出什么所以然來,大家既然想要學習這個語言就要去記下它的規則,所以還是得多寫多練,長時間不去用可能就忘記了。
總結一下其定義形式map[k]V,當然咱們也可以定義它比較復雜一些的數據結構,例如map里面套map,這種復合型的,那么定義的最終形式就是map[K1]map[K2]V。
對map的操作
查詢元素
我們定義出一個map之后,正常的邏輯就要去操作這個map,咱們先來看一下如何遍歷一個map,我想大家比較容易想到的就是我們講array的時候用的range函數的方式。確實,咱們可以寫成這樣,咱們就以一開始定義的m這個Map為例吧
for k,v :=range m {
fmt.Println(k,v)
}
這樣我們就可以獲取所有的數據,當然我們也可以根據對應的Key值獲取相關的value
name :=m["name"]
但是很多時候,我們是不能知道這個key是否存在的,我們取值的時候就要先判斷當前的key是否存在,然后再去獲取值,其實我們可以這樣寫
name,ok :=m["name"]
fmt.Println(name,ok) //結果輸出ktdaddy true
很顯然,我們可以通過ok的值去判斷當前的key是否存在,然后再去獲取其中的value值。那么結合前面所講的if條件語句,咱們就可以寫出這樣的邏輯
if name,ok :=m["name"];ok {
fmt.Println(name)
}else {
fmt.Println("key does not exist")
}
刪除元素
刪除元素其實是相當簡單的,用內置函數delete函數即可。我們還是承接上面的邏輯,如果發現存在這個Key值,那么我們就從map中進行移除。具體如下
if name,ok :=m["name"];ok {
delete(m,"name")
name,ok = m["name"]
fmt.Println(name,ok)
}else {
fmt.Println("key does not exist")
}
上述刪除之后咱們重新賦值map,這樣這個代碼最終輸出的結果就是false。大家可以實際動手練習一下。
字符串的處理
老貓想過好幾次,如何寫這個字符串,想要將其單獨抽出來說感覺也不合適,因為咱們很多時候會遍歷容器中的字符,因此索性就將其合並在內建容器里面一起分享好了。這里主要想和大家分享的是rune這個內建類型,從前面的章節中我們都知道這個相當於是Go的char,那么這個又怎么來用呢?咱們先來看下面例子
s:= "hello我愛GO開發"
fmt.Println(len(s))
大家覺得這個應該會輸出多少呢?試着運行一下,答案是19,那么為什么呢?我們再接着轉換成字節輸出一下
s:= "hello我愛GO開發"
fmt.Println(s)
fmt.Println(len(s))
fmt.Printf("%X\n",[]byte(s))
這樣呢,我們就獲取一段16進制的字節,結果如下
68656C6C6FE68891E788B1474FE5BC80E58F91
很顯然,我們還是無法看出來,我們將其格式做一下分割調整來看一下
s:= "hello我愛GO開發"
fmt.Println(s)
fmt.Println(len(s))
fmt.Printf("%X\n",[]byte(s))
for _,b:=range []byte(s) {
fmt.Printf("%X ",b)
}
運行的結果為 :68 65 6C 6C 6F E6 88 91 E7 88 B1 47 4F E5 BC 80 E5 8F 91
數一下成對出現的16進制數,咱們就可以發現19個字節長度原來是這么來的。通過分析我們不難發現一個英文占用了兩個字節而中文則占用了3個字節,例如里面的“我”轉換之后就是:E6 88 91,那么我們直接輸出s又會是什么呢?
for i,ch := range s{ // ch is a rune
fmt.Printf("(%d %X) ",i,ch)
}
fmt.Println()
結果為:
(0 68) (1 65) (2 6C) (3 6C) (4 6F) (5 6211) (8 7231) (11 47) (12 4F) (13 5F00) (16 53D1)
其實通過68 65 6C 6C 6F E6 88 91 E7 88 B1 47 4F E5 BC 80 E5 8F 91 轉換成了上面這個是通過什么轉換的呢?其實通過utf-8轉換成了unicode編碼,我們發現轉換成unicode之后,相關的中文字符編程了長度為4的16進制數,那么其實就是相當於是rune所占的字節長度了。
所以我們直接用rune對其進行轉換。
for i,ch :=range []rune(s){
fmt.Printf("(%d %c)",i,ch)
}
這樣我們就得到了如下
(0 h)(1 e)(2 l)(3 l)(4 o)(5 我)(6 愛)(7 G)(8 O)(9 開)(10 發)
如此,其實就遍歷獲取到了每個字符了。
當然,如果我們要統計utf-8下的字符長度,其實我們要對其進行轉換,在此介紹兩個函數
utf8.RuneCountInString(s)
utf8.DecodeRune(bytes)
通過這兩個函數,咱們可以獲取中文字符下的具體的字符個數了。
看起來比較零碎,咱們做一下總結,當然剩下還是得大家自己寫一下。
- 使用range遍歷pos,rune對
- 使用utf8.RuneCountInString(s)獲取字符數量
- 使用len獲取字節長度
- 使用[]byte獲取字節
總結
本次主要和大家分享了內建容器的剩余部分map的定義以及相關的操作使用,后面還和大家穿插了部分字符串的處理方式,當然還是比較散的,后面在寫項目的過程中,咱們到時候在具體用起來,所以在此希望大家持續關注老貓,另外的也希望大家多練習,一起進步,加油。
我是老貓,更多內容,歡迎大家搜索關注老貓的公眾號“程序員老貓”。

