• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            Fork me on GitHub
            隨筆 - 215  文章 - 13  trackbacks - 0
            <2017年3月>
            2627281234
            567891011
            12131415161718
            19202122232425
            2627282930311
            2345678


            專注即時通訊及網游服務端編程
            ------------------------------------
            Openresty 官方模塊
            Openresty 標準模塊(Opm)
            Openresty 三方模塊
            ------------------------------------
            本博收藏大部分文章為轉載,并在文章開頭給出了原文出處,如有再轉,敬請保留相關信息,這是大家對原創作者勞動成果的自覺尊重!!如為您帶來不便,請于本博下留言,謝謝配合。

            常用鏈接

            留言簿(1)

            隨筆分類

            隨筆檔案

            相冊

            Awesome

            Blog

            Book

            GitHub

            Link

            搜索

            •  

            積分與排名

            • 積分 - 216795
            • 排名 - 118

            最新評論

            閱讀排行榜

            http://www.jb51.net/article/56828.htm
            Array(數組)

            內部機制

            在 Go 語言中數組是固定長度的數據類型,它包含相同類型的連續的元素,這些元素可以是內建類型,像數字和字符串,也可以是結構類型,元素可以通過唯一的索引值訪問,從 0 開始。

            數組是很有價值的數據結構,因為它的內存分配是連續的,內存連續意味著可是讓它在 CPU 緩存中待更久,所以迭代數組和移動元素都會非常迅速。

            數組聲明和初始化

            通過指定數據類型和元素個數(數組長度)來聲明數組。

            復制代碼 代碼如下:

            // 聲明一個長度為5的整數數組
            var array [5]int

             

            一旦數組被聲明了,那么它的數據類型跟長度都不能再被改變。如果你需要更多的元素,那么只能創建一個你想要長度的新的數組,然后把原有數組的元素拷貝過去。

            Go 語言中任何變量被聲明時,都會被默認初始化為各自類型對應的 0 值,數組當然也不例外。當一個數組被聲明時,它里面包含的每個元素都會被初始化為 0 值。

            一種快速創建和初始化數組的方法是使用數組字面值。數組字面值允許我們聲明我們需要的元素個數并指定數據類型:

            復制代碼 代碼如下:

            // 聲明一個長度為5的整數數組
            // 初始化每個元素
            array := [5]int{7, 77, 777, 7777, 77777}

            如果你把長度寫成 ...,Go 編譯器將會根據你的元素來推導出長度:
            復制代碼 代碼如下:

            // 通過初始化值的個數來推導出數組容量
            array := [...]int{7, 77, 777, 7777, 77777}

             

            如果我們知道想要數組的長度,但是希望對指定位置元素初始化,可以這樣:

            復制代碼 代碼如下:

            // 聲明一個長度為5的整數數組
            // 為索引為1和2的位置指定元素初始化
            // 剩余元素為0值
            array := [5]int{1: 77, 2: 777}

             

            使用數組

            使用 [] 操作符來訪問數組元素:

            復制代碼 代碼如下:

            array := [5]int{7, 77, 777, 7777, 77777}
            // 改變索引為2的元素的值
            array[2] = 1

            我們可以定義一個指針數組:

             

            復制代碼 代碼如下:

            array := [5]*int{0: new(int), 1: new(int)}

             

            // 為索引為0和1的元素賦值
            *array[0] = 7
            *array[1] = 77


            在 Go 語言中數組是一個值,所以可以用它來進行賦值操作。一個數組可以被賦值給任意相同類型的數組:

             

            復制代碼 代碼如下:

            var array1 [5]string
            array2 := [5]string{"Red", "Blue", "Green", "Yellow", "Pink"}
            array1 = array2

            注意數組的類型同時包括數組的長度和可以被存儲的元素類型,數組類型完全相同才可以互相賦值,比如下面這樣就不可以:
            復制代碼 代碼如下:

            var array1 [4]string
            array2 := [5]string{"Red", "Blue", "Green", "Yellow", "Pink"}
            array1 = array2

             

            // 編譯器會報錯
            Compiler Error:
            cannot use array2 (type [5]string) as type [4]string in assignment


            拷貝一個指針數組實際上是拷貝指針值,而不是指針指向的值:
            復制代碼 代碼如下:

            var array1 [3]*string
            array2 := [3]*string{new(string), new(string), new(string)}
            *array2[0] = "Red"
            *array2[1] = "Blue"
            *array2[2] = "Green"

             

            array1 = array2
            // 賦值完成后,兩組指針數組指向同一字符串

             

            多維數組

            數組總是一維的,但是可以組合成多維的。多維數組通常用于有父子關系的數據或者是坐標系數據:

            復制代碼 代碼如下:

            // 聲明一個二維數組
            var array [4][2]int

             

            // 使用數組字面值聲明并初始化
            array := [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}}

            // 指定外部數組索引位置初始化
            array := [4][2]int{1: {20, 21}, 3: {40, 41}}

            // 同時指定內外部數組索引位置初始化
            array := [4][2]int{1: {0: 20}, 3: {1: 41}}

             

            同樣通過 [] 操作符來訪問數組元素:

            復制代碼 代碼如下:

            var array [2][2]int

             

            array[0][0] = 0
            array[0][1] = 1
            array[1][0] = 2
            array[1][1] = 3

             

            也同樣的相同類型的多維數組可以相互賦值:

            復制代碼 代碼如下:

            var array1 = [2][2]int
            var array2 = [2][2]int

             

            array[0][0] = 0
            array[0][1] = 1
            array[1][0] = 2
            array[1][1] = 3

            array1 = array2

             

            因為數組是值,我們可以拷貝單獨的維:

            復制代碼 代碼如下:

            var array3 [2]int = array1[1]
            var value int = array1[1][0]

             

            在函數中傳遞數組

            在函數中傳遞數組是非常昂貴的行為,因為在函數之間傳遞變量永遠是傳遞值,所以如果變量是數組,那么意味著傳遞整個數組,即使它很大很大很大。。。

            舉個栗子,創建一個有百萬元素的整形數組,在64位的機器上它需要8兆的內存空間,來看看我們聲明它和傳遞它時發生了什么:

            復制代碼 代碼如下:

            var array [1e6]int
            foo(array)
            func foo(array [1e6]int) {
              ...
            }

            每一次 foo 被調用,8兆內存將會被分配在棧上。一旦函數返回,會彈棧并釋放內存,每次都需要8兆空間。

             

            Go 語言當然不會這么傻,有更好的方法來在函數中傳遞數組,那就是傳遞指向數組的指針,這樣每次只需要分配8字節內存:

            復制代碼 代碼如下:

            var array [1e6]int
            foo(&array)
            func foo(array *[1e6]int){
              ...
            }

             

            但是注意如果你在函數中改變指針指向的值,那么原始數組的值也會被改變。幸運的是 slice(切片)可以幫我們處理好這些問題,來一起看看。

            Slice(切片)

            內部機制和基礎

            slice 是一種可以動態數組,可以按我們的希望增長和收縮。它的增長操作很容易使用,因為有內建的 append 方法。我們也可以通過 relice 操作化簡 slice。因為 slice 的底層內存是連續分配的,所以 slice 的索引,迭代和垃圾回收性能都很好。

            slice 是對底層數組的抽象和控制。它包含 Go 需要對底層數組管理的三種元數據,分別是:

            1.指向底層數組的指針
            2.slice 中元素的長度
            3.slice 的容量(可供增長的最大值)

            創建和初始化

            Go 中創建 slice 有很多種方法,我們一個一個來看。

            第一個方法是使用內建的函數 make。當我們使用 make 創建時,一個選項是可以指定 slice 的長度:

            復制代碼 代碼如下:

            slice := make([]string, 5)

             

            如果只指定了長度,那么容量默認等于長度。我們可以分別指定長度和容量:

            復制代碼 代碼如下:

            slice := make([]int, 3, 5)

            當我們分別指定了長度和容量,我們創建的 slice 就可以擁有一開始并沒有訪問的底層數組的容量。上面代碼的 slice 中,可以訪問3個元素,但是底層數組有5個元素。兩個與長度不相干的元素可以被 slice 來用。新創建的 slice 同樣可以共享底層數組和已存在的容量。

             

            不允許創建長度大于容量的 slice:

            復制代碼 代碼如下:

            slice := make([]int, 5, 3)

             

            Compiler Error:
            len larger than cap in make([]int)

             

            慣用的創建 slice 的方法是使用 slice 字面量。跟創建數組很類似,不過不用指定 []里的值。初始的長度和容量依賴于元素的個數:

            復制代碼 代碼如下:

            // 創建一個字符串 slice
            // 長度和容量都是 5
            slice := []string{"Red", "Blue", "Green", "Yellow", "Pink"}

             

            在使用 slice 字面量創建 slice 時有一種方法可以初始化長度和容量,那就是初始化索引。下面是個例子:

            復制代碼 代碼如下:

            // 創建一個字符串 slice
            // 初始化一個有100個元素的空的字符串 slice
            slice := []string{99: ""}

             

            nil 和 empty slice

            有的時候我們需要創建一個 nil slice,創建一個 nil slice 的方法是聲明它但不初始化它:

            復制代碼 代碼如下:

            var slice []int

             

            創建一個 nil slice 是創建 slice 最基本的方法,很多標準庫和內建函數都可以使用它。當我們想要表示一個并不存在的 slice 時它變得非常有用,比如一個返回 slice 的函數中發生異常的時候。

            創建 empty slice 的方法就是聲明并初始化一下:

            復制代碼 代碼如下:

            // 使用 make 創建
            silce := make([]int, 0)

             

            // 使用 slice 字面值創建
            slice := []int{}

             

            empty slice 包含0個元素并且底層數組沒有分配存儲空間。當我們想要表示一個空集合時它很有用處,比如一個數據庫查詢返回0個結果。

            不管我們用 nil slice 還是 empty slice,內建函數 append,len和cap的工作方式完全相同。

            使用 slice

            為一個指定索引值的 slice 賦值跟之前數組賦值的做法完全相同。改變單個元素的值使用 [] 操作符:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30, 40, 50}
            slice[1] = 25

             

            我們可以在底層數組上對一部分數據進行 slice 操作,來創建一個新的 slice:

            復制代碼 代碼如下:

            // 長度為5,容量為5
            slice := []int{10, 20, 30, 40, 50}

             

            // 長度為2,容量為4
            newSlice := slice[1:3]

             

            在 slice 操作之后我們得到了兩個 slice,它們共享底層數組。但是它們能訪問底層數組的范圍卻不同,newSlice 不能訪問它頭指針前面的值。

            計算任意 new slice 的長度和容量可以使用下面的公式:

            復制代碼 代碼如下:

            對于 slice[i:j] 和底層容量為 k 的數組
            長度:j - i
            容量:k - i

             

            必須再次明確一下現在是兩個 slice 共享底層數組,因此只要有一個 slice 改變了底層數組的值,那么另一個也會隨之改變:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30, 40, 50}
            newSlice := slice[1:3]
            newSlice[1] = 35

             

            改變 newSlice 的第二個元素的值,也會同樣改變 slice 的第三個元素的值。

            一個 slice 只能訪問它長度范圍內的索引,試圖訪問超出長度范圍的索引會產生一個運行時錯誤。容量只可以用來增長,它只有被合并到長度才可以被訪問:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30, 40, 50}
            newSlice := slice[1:3]
            newSlice[3] = 45

             

            Runtime Exception:
            panic: runtime error: index out of range

             

            容量可以被合并到長度里,通過內建的 append 函數。

            slice 增長

            slice 比 數組的優勢就在于它可以按照我們的需要增長,我們只需要使用 append 方法,然后 Go 會為我們做好一切。

            使用 append 方法時我們需要一個源 slice 和需要附加到它里面的值。當 append 方法返回時,它返回一個新的 slice,append 方法總是增長 slice 的長度,另一方面,如果源 slice 的容量足夠,那么底層數組不會發生改變,否則會重新分配內存空間。

            復制代碼 代碼如下:

            // 創建一個長度和容量都為5的 slice
            slice := []int{10, 20, 30, 40, 50}

             

            // 創建一個新的 slice
            newSlice := slice[1:3]

            // 為新的 slice append 一個值
            newSlice = append(newSlice, 60)

             

            因為 newSlice 有可用的容量,所以在 append 操作之后 slice 索引為 3 的值也變成了 60,之前說過這是因為 slice 和 newSlice 共享同樣的底層數組。

            如果沒有足夠可用的容量,append 函數會創建一個新的底層數組,拷貝已存在的值和將要被附加的新值:

            復制代碼 代碼如下:

            // 創建長度和容量都為4的 slice
            slice := []int{10, 20, 30, 40}

             

            // 附加一個新值到 slice,因為超出了容量,所以會創建新的底層數組
            newSlice := append(slice, 50)

             

            append 函數重新創建底層數組時,容量會是現有元素的兩倍(前提是元素個數小于1000),如果元素個數超過1000,那么容量會以 1.25 倍來增長。

            slice 的第三個索引參數

            slice 還可以有第三個索引參數來限定容量,它的目的不是為了增加容量,而是提供了對底層數組的一個保護機制,以方便我們更好的控制 append 操作,舉個栗子:

            復制代碼 代碼如下:

            source := []string{"apple", "orange", "plum", "banana", "grape"}

             

            // 接著我們在源 slice 之上創建一個新的 slice
            slice := source[2:3:4]

             

            新創建的 slice 長度為 1,容量為 2,可以看出長度和容量的計算公式也很簡單:

            復制代碼 代碼如下:

            對于 slice[i:j:k]  或者 [2:3:4]

             

            長度: j - i       或者   3 - 2
            容量: k - i       或者   4 - 2

             

            如果我們試圖設置比可用容量更大的容量,會得到一個運行時錯誤:

            復制代碼 代碼如下:

            slice := source[2:3:6]

             


            Runtime Error:
            panic: runtime error: slice bounds out of range

             

            限定容量最大的用處是我們在創建新的 slice 時候限定容量與長度相同,這樣以后再給新的 slice 增加元素時就會分配新的底層數組,而不會影響原有 slice 的值:

            復制代碼 代碼如下:

            source := []string{"apple", "orange", "plum", "banana", "grape"}

             

            // 接著我們在源 slice 之上創建一個新的 slice
            // 并且設置長度和容量相同
            slice := source[2:3:3]

            // 添加一個新元素
            slice = append(slice, "kiwi")

             

            如果沒有第三個索引參數限定,添加 kiwi 這個元素時就會覆蓋掉 banana。

            內建函數 append 是一個變參函數,意思就是你可以一次添加多個元素,比如:

            復制代碼 代碼如下:

            s1 := []int{1, 2}
            s2 := []int{3, 4}

             

            fmt.Printf("%v\n", append(s1, s2...))

            Output:
            [1 2 3 4]

             

            迭代 slice

            slice 也是一種集合,所以可以被迭代,用 for 配合 range 來迭代:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30, 40, 50}

             

            for index, value := range slice {
              fmt.Printf("Index: %d  Value: %d\n", index, value)
            }

            Output:
            Index: 0  Value: 10
            Index: 1  Value: 20
            Index: 2  Value: 30
            Index: 3  Value: 40
            Index: 4  Value: 50

             

            當迭代時 range 關鍵字會返回兩個值,第一個是索引值,第二個是索引位置值的拷貝。注意:返回的是值的拷貝而不是引用,如果我們把值的地址作為指針使用,會得到一個錯誤,來看看為啥:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30 ,40}

             

            for index, value := range slice {
              fmt.Printf("Value: %d  Value-Addr: %X  ElemAddr: %X\n", value, &value, &slice[index])
            }

            Output:
            Value: 10  Value-Addr: 10500168  ElemAddr: 1052E100
            Value: 20  Value-Addr: 10500168  ElemAddr: 1052E104
            Value: 30  Value-Addr: 10500168  ElemAddr: 1052E108
            Value: 40  Value-Addr: 10500168  ElemAddr: 1052E10C

             

            value 變量的地址總是相同的因為它只是包含一個拷貝。如果想得到每個元素的真是地址可以使用 &slice[index]。

            如果不需要索引值,可以使用 _ 操作符來忽略它:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30, 40}

             

            for _, value := range slice {
              fmt.Printf("Value: %d\n", value)
            }


            Output:
            Value: 10
            Value: 20
            Value: 30
            Value: 40

             

            range 總是從開始一次遍歷,如果你想控制遍歷的step,就用傳統的 for 循環:

            復制代碼 代碼如下:

            slice := []int{10, 20, 30, 40}

             

            for index := 2; index < len(slice); index++ {
              fmt.Printf("Index: %d  Value: %d\n", index, slice[index])
            }


            Output:
            Index: 2  Value: 30
            Index: 3  Value: 40

             

            同數組一樣,另外兩個內建函數 len 和 cap 分別返回 slice 的長度和容量。

            多維 slice

            也是同數組一樣,slice 可以組合為多維的 slice:

            復制代碼 代碼如下:

            slice := [][]int{{10}, {20, 30}}

             

            需要注意的是使用 append 方法時的行為,比如我們現在對 slice[0] 增加一個元素:

            復制代碼 代碼如下:

            slice := [][]int{{10}, {20, 30}}
            slice[0] = append(slice[0], 20)

             

            那么只有 slice[0] 會重新創建底層數組,slice[1] 則不會。

            在函數間傳遞 slice

            在函數間傳遞 slice 是很廉價的,因為 slice 相當于是指向底層數組的指針,讓我們創建一個很大的 slice 然后傳遞給函數調用它:

            復制代碼 代碼如下:

            slice := make([]int, 1e6)

             

            slice = foo(slice)

            func foo(slice []int) []int {
                ...
                return slice
            }

             

            Map

            內部機制

            map 是一種無序的鍵值對的集合。map 最重要的一點是通過 key 來快速檢索數據,key 類似于索引,指向數據的值。

            map 是一種集合,所以我們可以像迭代數組和 slice 那樣迭代它。不過,map 是無序的,我們無法決定它的返回順序,這是因為 map 是使用 hash 表來實現的。

            map 的 hash 表包含了一個桶集合(collection of buckets)。當我們存儲,移除或者查找鍵值對(key/value pair)時,都會從選擇一個桶開始。在映射(map)操作過程中,我們會把指定的鍵值(key)傳遞給 hash 函數(又稱散列函數)。hash 函數的作用是生成索引,索引均勻的分布在所有可用的桶上。hash 表算法詳見:July的博客—從頭到尾徹底解析 hash 表算法

            創建和初始化

            Go 語言中有多種方法創建和初始化 map。我們可以使用內建函數 make 也可以使用 map 字面值:

            復制代碼 代碼如下:

            // 通過 make 來創建
            dict := make(map[string]int)

             

            // 通過字面值創建
            dict := map[string]string{"Red": "#da1337", "Orange": "#e95a22"}

             

             

            使用字面值是創建 map 慣用的方法(為什么不使用make)。初始化 map 的長度依賴于鍵值對的數量。

            map 的鍵可以是任意內建類型或者是 struct 類型,map 的值可以是使用 ==操作符的表達式。slice,function 和 包含 slice 的 struct 類型不可以作為 map 的鍵,否則會編譯錯誤:

            復制代碼 代碼如下:

            dict := map[[]string]int{}

             

            Compiler Exception:
            invalid map key type []string

             

            使用 map

            給 map 賦值就是指定合法類型的鍵,然后把值賦給鍵:

            復制代碼 代碼如下:

            colors := map[string]string{}
            colors["Red"] = "#da1337"

             

            如果不初始化 map,那么就會創建一個 nil map。nil map 不能用來存放鍵值對,否則會報運行時錯誤:

            復制代碼 代碼如下:

            var colors map[string]string
            colors["Red"] = "#da1337"

             

            Runtime Error:
            panic: runtime error: assignment to entry in nil map

             

            測試 map 的鍵是否存在是 map 操作的重要部分,因為它可以讓我們判斷是否可以執行一個操作,或者是往 map 里緩存一個值。它也可以被用來比較兩個 map 的鍵值對是否匹配或者缺失。

            從 map 里檢索一個值有兩種選擇,我們可以同時檢索值并且判斷鍵是否存在:

            復制代碼 代碼如下:

            value, exists := colors["Blue"]
            if exists {
              fmt.Println(value)
            }

             

            另一種選擇是只返回值,然后判斷是否是零值來確定鍵是否存在。但是只有你確定零值是非法值的時候這招才管用:

            復制代碼 代碼如下:

            value := colors["Blue"]
            if value != "" {
              fmt.Println(value)
            }

             

            當索引一個 map 取值時它總是會返回一個值,即使鍵不存在。上面的例子就返回了對應類型的零值。

            迭代一個 map 和迭代數組和 slice 是一樣的,使用 range 關鍵字,不過在迭代 map 時我們不使用 index/value 而使用 key/value 結構:

            復制代碼 代碼如下:

            colors := map[string]string{
                "AliceBlue":   "#f0f8ff",
                "Coral":       "#ff7F50",
                "DarkGray":    "#a9a9a9",
                "ForestGreen": "#228b22",
            }

             

            for key, value := range colors {
              fmt.Printf("Key: %s  Value: %s\n", key, value)
            }

             

            如果我們想要從 map 中移除一個鍵值對,使用內建函數 delete(要是也能返回移除是否成功就好了,哎。。。):

            復制代碼 代碼如下:

            delete(colors, "Coral")

             

            for key, value := range colors {
              fmt.Println("Key: %s  Value: %s\n", key, value)
            }

             

            在函數間傳遞 map

            在函數間傳遞 map 不是傳遞 map 的拷貝。所以如果我們在函數中改變了 map,那么所有引用 map 的地方都會改變:

            復制代碼 代碼如下:

            func main() {
              colors := map[string]string{
                 "AliceBlue":   "#f0f8ff",
                 "Coral":       "#ff7F50",
                 "DarkGray":    "#a9a9a9",
                 "ForestGreen": "#228b22",
              }

             

              for key, value := range colors {
                  fmt.Printf("Key: %s  Value: %s\n", key, value)
              }

              removeColor(colors, "Coral")

              for key, value := range colors {
                  fmt.Printf("Key: %s  Value: %s\n", key, value)
              }
            }

            func removeColor(colors map[string]string, key string) {
                delete(colors, key)
            }

             

            執行會得到以下結果:

            復制代碼 代碼如下:

            Key: AliceBlue Value: #F0F8FF
            Key: Coral Value: #FF7F50
            Key: DarkGray Value: #A9A9A9
            Key: ForestGreen Value: #228B22
               
            Key: AliceBlue Value: #F0F8FF
            Key: DarkGray Value: #A9A9A9
            Key: ForestGreen Value: #228B22

             

            可以看出來傳遞 map 也是十分廉價的,類似 slice。

            Set

            Go 語言本身是不提供 set 的,但是我們可以自己實現它,下面就來試試:

            復制代碼 代碼如下:

            package main

             

            import(
              "fmt"
              "sync"
            )

            type Set struct {
              m map[int]bool
              sync.RWMutex
            }

            func New() *Set {
              return &Set{
                m: map[int]bool{},
              }
            }

            func (s *Set) Add(item int) {
              s.Lock()
              defer s.Unlock()
              s.m[item] = true
            }

            func (s *Set) Remove(item int) {
              s.Lock()
              s.Unlock()
              delete(s.m, item)
            }

            func (s *Set) Has(item int) bool {
              s.RLock()
              defer s.RUnlock()
              _, ok := s.m[item]
              return ok
            }

            func (s *Set) Len() int {
              return len(s.List())
            }

            func (s *Set) Clear() {
              s.Lock
              defer s.Unlock()
              s.m = map[int]bool{}
            }

            func (s *Set) IsEmpty() bool {
              if s.Len() == 0 {
                return true
              }
              return false
            }

            func (s *Set) List() []int {
              s.RLock()
              defer s.RUnlock()
              list := []int{}
              for item := range s.m {
                list = append(list, item)
              }
              return list
            }

            func main() {
              // 初始化
              s := New()
             
              s.Add(1)
              s.Add(1)
              s.Add(2)

              s.Clear()
              if s.IsEmpty() {
                fmt.Println("0 item")
              }
             
              s.Add(1)
              s.Add(2)
              s.Add(3)
             
              if s.Has(2) {
                fmt.Println("2 does exist")
              }
             
              s.Remove(2)
              s.Remove(3)
              fmt.Println("list of all items", S.List())
            }

             

            注意我們只是使用了 int 作為鍵,你可以自己實現用 interface{} 作為鍵,做成更通用的 Set,另外,這個實現是線程安全的。

            總結

            1.數組是 slice 和 map 的底層結構。
            2.slice 是 Go 里面慣用的集合數據的方法,map 則是用來存儲鍵值對。
            3.內建函數 make 用來創建 slice 和 map,并且為它們指定長度和容量等等。slice 和 map 字面值也可以做同樣的事。
            4.slice 有容量的約束,不過可以通過內建函數 append 來增加元素。
            5.map 沒有容量一說,所以也沒有任何增長限制。
            6.內建函數 len 可以用來獲得 slice 和 map 的長度。
            7.內建函數 cap 只能作用在 slice 上。
            8.可以通過組合方式來創建多維數組和 slice。map 的值可以是 slice 或者另一個 map。slice 不能作為 map 的鍵。
            9.在函數之間傳遞 slice 和 map 是相當廉價的,因為他們不會傳遞底層數組的拷貝。

            posted on 2016-01-13 15:17 思月行云 閱讀(387) 評論(0)  編輯 收藏 引用 所屬分類: Golang
            国产成人精品久久| 久久久久人妻一区精品| 亚洲精品无码专区久久久| 人妻精品久久无码区| 免费观看久久精彩视频| 国产精品一区二区久久精品无码| 久久久久久av无码免费看大片| 久久天天躁狠狠躁夜夜2020老熟妇| 亚洲午夜福利精品久久| 99国产精品久久久久久久成人热| 国产激情久久久久影院老熟女免费 | 久久香蕉国产线看观看精品yw| 日韩欧美亚洲综合久久影院d3| 国内精品久久久久久久久电影网| 久久这里只有精品久久| 伊人久久久AV老熟妇色| 色偷偷88欧美精品久久久| 蜜桃麻豆www久久| 99久久人妻无码精品系列蜜桃| 久久国产精品无| 久久久久人妻一区精品| 国内精品久久久久影院网站| 国产综合久久久久久鬼色| 久久精品中文字幕一区| 亚洲国产成人精品91久久久| 色综合久久最新中文字幕| 男女久久久国产一区二区三区| 国产99久久久国产精品小说| 亚洲人AV永久一区二区三区久久| 99久久精品免费国产大片| 99久久免费国产特黄| 精品久久一区二区三区| 久久99毛片免费观看不卡| 91精品国产乱码久久久久久| 日产精品久久久久久久| 男女久久久国产一区二区三区| 综合久久国产九一剧情麻豆| 久久精品国产AV一区二区三区| 久久www免费人成看片| 色婷婷久久综合中文久久蜜桃av | 欧美精品国产综合久久|