<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] 切片也是一種數據結構,它和數組非常相似,是圍繞 *動態數組* 的概念設計的,可以按需自動改變大小,使用這種結構,可以更方便的管理和使用數據集合。 > 本質是結構體 ## 概念 * 其本身并不是數組,它指向底層數組 * 作為變長數組的替代方案,可以關聯底層數組的局部或者全部 * 為引用類型 * 可以直接創建或從底層數組生成 * 一般使用`make`創建 * 如果多個切片指向相同的底層數組,其中一個值改變會影響全部 * `meke([]T,len,cap)` cap省略時和len相同 * `len()`獲取元素個數,cap()獲取容量 ## 內部實現 切片是基于數組實現的,它的底層是數組,它自己本身非常小,可以理解為對底層數組的抽象。因為基于數組實現,所以它的底層的內存是連續分配的,效率非常高,還可以通過索引獲得數據,可以迭代以及垃圾回收優化的好處。 切片對象非常小,是因為它是只有3個字段的數據結構: 1. 指向底層數組的指針 2. 切片的長度 3. 切片的容量 這3個字段,就是Go語言操作底層數組的元數據,有了它們,我們就可以任意的操作切片了。 ## 切片內部結構,實質是結構體 ![](https://gitee.com/echohiyang/markdown-images/raw/master/vx4CNF.jpg) ## 切片共享存儲結構 ![](https://gitee.com/echohiyang/markdown-images/raw/master/0OwLbR.jpg) ## 聲明和初始化 ### make方式 ~~~ slice := make([]int,5) slice := make([]int,5,10) ~~~ 使用內置的make函數時,需要傳入一個參數,指定切片的`長度`,例子中我們使用的時5,這時候切片的容量也是5。可以第二個參數單獨指定切片的容量。這個容量10其實對應的是`切片底層數組`的。 因為切片的底層是數組,所以創建切片時,如果不指定字面值的話,默認值就是數組的元素的零值。這里我們所以指定了容量是10,但是我們職能訪問5個元素,因為切片的長度是5,剩下的5個元素,需要切片擴充后才可以訪問。 容量必須>=長度,我們是不能創建長度大于容量的切片的。 ### 使用字面量 就是指定初始化的值。 ~~~ slice := []int{1,2,3,4,5} slice := []int{4:1} ~~~ 此時切片的長度和容量是相等的,并且會根據我們指定的字面量推導出來。 ### 基于現有的數組或者切片創建 ~~~ slice := []int{1, 2, 3, 4, 5} slice1 := slice[:] slice2 := slice[0:] slice3 := slice[:5] fmt.Println(slice1) fmt.Println(slice2) fmt.Println(slice3) ~~~ ### 共用底層數組 ~~~ slice := []int{1, 2, 3, 4, 5} newSlice := slice[1:3] newSlice[0] = 10 fmt.Println(slice) fmt.Println(newSlice) ~~~ 這個例子證明了,新的切片和原切片共用的是一個底層數組,所以當修改的時候,底層數組的值就會被改變,所以原切片的值也改變了。當然對于基于數組的切片也一樣的。 ## 使用切片 使用切片,和使用數組一樣,通過索引就可以獲取切片對應元素的值,同樣也可以修改對應元素的值。 ~~~ slice := []int{1, 2, 3, 4, 5} fmt.Println(slice[2]) //獲取值 slice[2] = 10 //修改值 fmt.Println(slice[2]) //輸出10 ~~~ 切片只能訪問到其長度內的元素,訪問超過長度外的元素,會導致運行時異常,與切片容量關聯的元素只能用于切片增長。 ### append 切片算是一個動態數組,所以它可以按需增長,我們使用內置append函數即可。append函數可以為一個切片追加一個元素,至于如何增加、返回的是原切片還是一個新切片、長度和容量如何改變這些細節,append函數都會幫我們自動處理。 內置的append也是一個可變參數的函數,所以我們可以同時追加好幾個值。 ~~~ slice := []int{1, 2, 3, 4, 5} newSlice := slice[1:3] newSlice=append(newSlice,10) fmt.Println(newSlice) fmt.Println(slice) //Output [2 3 10] [1 2 3 10 5] newSlice=append(newSlice, newSlice...) ~~~ 例子中,通過append函數為新創建的切片newSlice,追加了一個元素10,我們發現打印的輸出,原切片slice的第4個值也被改變了,變成了10。引起這種結果的原因是因為newSlice有可用的容量,不會創建新的切片來滿足追加,所以直接在newSlice后追加了一個元素10,因為newSlice和slice切片共用一個底層數組,所以切片slice的對應的元素值也被改變了。 這里newSlice新追加的第3個元素,其實對應的是slice的第4個元素,所以這里的追加其實是把底層數組的第4個元素修改為10,然后把newSlice長度調整為3。 >[danger]如果切片的底層數組,沒有足夠的容量時,就會新建一個底層數組,把原來數組的值復制到新底層數組里,再追加新值,這時候就不會影響原來的底層數組了。 >[info]所以一般我們在創建新切片的時候,最好要讓新切片的長度和容量一樣,這樣我們在追加操作的時候就會生成新的底層數組,和原有數組分離,就不會因為共用底層數組而引起奇怪問題,因為共用數組的時候修改內容,會影響多個切片。 append函數會智能的增長底層數組的容量,目前的算法是:容量小于1000個時,總是成倍的增長,一旦容量超過1000個,增長因子設為1.25,也就是說每次會增加25%的容量。 ## copy 拷貝切片 這里的 copy 不是引用傳遞,切片起始指針會改變 ~~~ s1 := []int{1, 2,3, 4, 5} s2 := make([]int, 5) copy(s2, s1) fmt.Printf("%p\n", s1) fmt.Printf("%p\n", s2) ~~~ ## 迭代切片 ### for range循環 切片是一個集合,我們可以使用 for range 循環來迭代它,打印其中的每個元素以及對應的索引。 ~~~ slice := []int{1, 2, 3, 4, 5} for i,v:=range slice{ fmt.Printf("索引:%d,值:%d\n",i,v) } ~~~ ## 傳統的for循環 配合內置的len函數進行迭代。 slice := []int{1, 2, 3, 4, 5} for i := 0; i < len(slice); i++ { fmt.Printf("值:%d\n", slice[i]) } ## 在函數間傳遞切片 slice 是引用傳遞。 我們知道切片是3個字段構成的結構類型,所以在函數間以值的方式傳遞的時候,占用的內存非常小,成本很低。在傳遞復制切片的時候,其底層數組不會被復制,也不會受影響,復制只是復制的切片本身,不涉及底層數組。 ~~~ func main() { slice := []int{1, 2, 3, 4, 5} fmt.Printf("%p\n", &slice) modify(slice) fmt.Println(slice) } func modify(slice []int) { fmt.Printf("%p\n", &slice) slice[1] = 10 } ~~~ 打印的輸出如下: ~~~ 0xc420082060 0xc420082080 [1 10 3 4 5] ~~~ 仔細看,這兩個切片的地址不一樣,所以可以確認切片在函數間傳遞是復制的。而我們修改一個索引的值后,發現原切片的值也被修改了,說明它們共用一個底層數組。 在函數間傳遞切片非常高效,而且不需要傳遞指針和處理復雜的語法,只需要復制切片,然后根據自己的業務修改,最后傳遞回一個新的切片副本即可,這也是為什么函數間傳遞參數,使用切片,而不是數組的原因。 ## string 與 slice string 底層是一個 byte 的數組,有也可以進行切片操作。 ``` str := "hello world" s1 := str[0:5] fmt.Println(s1) ``` ## 利用切片對數組排序 ``` package main import ( "fmt" "sort" ) func testInts() { a := [...]int{11,4,2,3,9,20} sort.Ints(a[:]) fmt.Println(a) } func testStrings() { s := [...]string{"ac", "a", "ab", "AC", "A", "AB"} sort.Strings(s[:]) fmt.Println(s) } func testFload64s() { f := [...]float64{3.1415, 2.713, 1.024, 1024} sort.Float64s(f[:]) fmt.Println(f) } func main() { testInts() testStrings() testFload64s() } ``` ### 查找索引 ``` sort.SearchInts(a []int, b int) 從數組 a 中查找 b 的索引,前提是 a 已經排序 sort.SearchFloats(a []int, b int) 從數組 a 中查找 b 的索引,前提是 a 已經排序 sort.SearchStrings(a []int, b int) 從數組 a 中查找 b 的索引,前提是 a 已經排序 ``` ## nil切片和空切片 它們的長度和容量都是0,但是它們指向底層數組的指針不一樣。 nil切片意味著指向底層數組的指針為nil,表示不存在的切片; 空切片對應的指針是個地址,空切片表示一個空集合。 ~~~ //nil切片 var nilSlice []int //空切片 slice := []int{} ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看