Go map定義的幾種方式以及修改技巧

原文鏈接:http://www.zhoubotong.site/post/24.html
直入正題,我們看下以下代碼:

package main

import (
   "encoding/json"
   "fmt"
)

func main() {
   //第一種聲明
   var language map[string]string

   language = make(map[string]string, 10) //在使用map前,需要先make,make的作用就是給map分配數據空間
   language["1"] = "C#"
   language["2"] = "go"
   language["3"] = "python"
   fmt.Println(language) //map[1:C# 2:go 3:python]

   //第二種聲明 相比上面的第一種,少了 var聲明
   language2 := make(map[string]string)
   language2["1"] = "C#"
   language2["2"] = "go"
   language2["3"] = "python"
   fmt.Println(language2) //map[1:C# 2:go 3:python]

   //第三種聲明 直接初始化
   language3 := map[string]string{
      "1": "C#",
      "2": "go",
      "3": "python",
   }
   fmt.Println(language3) //map[1:C# 2:go 3:python]

   language4 := make(map[string]map[string]string) // 這裏鍵值對:string => map[string]string,簡單理解就是[string][string]=>string
   language4["python"] = make(map[string]string, 2)
   language4["python"]["id"] = "1"
   language4["python"]["desc"] = "python是世界上最好的語言"
   language4["go"] = make(map[string]string, 2)
   language4["go"]["id"] = "2"
   language4["go"]["desc"] = "go是世界上最好的語言"

   fmt.Println(language4) //map[go:map[desc:go是世界上最好的語言 id:2] python:map[desc:python是世界上最好的語言 id:1]]

   //增刪改查
   val, key := language4["java"] //查找是否有java這個子元素
   if key {
      fmt.Println(val)
   } else {
      fmt.Println("找不到key")
   }

   //language4["go"]["id"] = "3" //修改了go子元素的id值,注意這裏是修改,不要理解成是追加元素
   //language4["go"]["name"] = "golang性能最佳" //增加go元素裏的name值
   //delete(language4, "python")  //刪除了python子元素
   //fmt.Println(language4)
   mjson, _ := json.Marshal(language4)
   mString := string(mjson)
   fmt.Printf("json String:%s", mString)
}

上面給了一個綜合示例,很多時候需要將遍歷對象中去掉某些元素,或者往遍歷對象中添加元素,這時候就需要小心操作了。

對於go語言中的一些注意事項我做了一些總結和示例,也留下點筆記。我們繼續舉幾個例子:

遍歷切片

  1. 遍歷切片時去掉元素,錯誤示例:

    package main
    
    import (
       "fmt"
    )
    
    func main() {
       arr := []int{1, 2, 3, 4}
       for i := range arr {
          if arr[i] == 3 { // 即此時 下標爲 2
             println(len(arr))
             //arr = append(arr[:i], arr[i+1:]...) //因爲range在迭代時已經確定i的範圍爲[0,len(arr))的左閉右開的區間即[0,3)。
             //當滿足arr[i] == 3時對arr進行了修改,縮短了arr的長度,此時len(arr)=3,最大下標爲2,因此當執行arr[3]時會報錯。因爲溢出了
          }
       }
       fmt.Println(arr)
    } //panic: runtime error: index out of range [3] with length 3

    那如何正確刪除指定切片元素?我們稍微改下:
    遍歷切片時去掉元素,不會報錯,但不建議的寫法:

    package main
    
    import (
       "fmt"
    )
    
    func main() {
       arr := []int{1, 2, 3, 4}
       for i, v := range arr {
          if v == 3 {
             arr = append(arr[:i], arr[i+1:]...) // arr[:i] 即爲arr[:2]=> []int{1, 2}, arr[i+1:]即爲:arr[3:] =>[]int{4}
          }
       }
       fmt.Println(arr)
    } // 輸出 [1 2 4]

    解釋:
    還是回到range的用法,當執行for循環時就已經確定(i,v)的遍歷元素值,及時循環過程中修改了arr,也不會改變for要遍歷的(i,v)值。
    可以將上面代碼修改一下,看下在循環中改變arr值時,後面遍歷的(i,v)是不會隨着arr的改變而改變的。繼續往下看:
    遍歷切片時去掉元素,建議寫法:

    package main
    
    import (
       "fmt"
    )
    
    func main() {
       arr := []int{1, 2, 3, 4}
       for i := 0; i < len(arr); i++ {
          fmt.Println(i, arr[i])
          if arr[i] == 3 {
             fmt.Println("i--之前=", i)
             arr = append(arr[:i], arr[i+1:]...) //arr[:2],arr[3:]
             i--
             fmt.Println("i--之後=", i)
          }
       }
       fmt.Println(arr)
    }

    輸出:

    0 1
    1 2
    2 3
    i--之前= 2
    i--之後= 1
    2 4
    [1 2 4]

    解釋:

        該方案只修改i的值,在刪除元素時進行i--,可以確保遍歷arr沒有問題,而且每次通過arr[i]獲取切片值不存在問題。

        當然用該方式也可以在遍歷時添加元素,只要i也對應變化就沒問題。

        總結:

        關於切片遍歷時進行操作需要注意一些坑。

        map遍歷時進行操作相對坑少點,不過遍歷map需要修改元素時,map的value要爲指針類型,這點值得謹記。

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