<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] ## 7.2.1 概念 切片(slice)是對數組一個連續片段的引用(該數組我們稱之為相關數組,通常是匿名的),所以切片是一個引用類型(因此更類似于 C/C++ 中的數組類型,或者 Python 中的 list 類型)。這個片段可以是整個數組,或者是由起始和終止索引標識的一些項的子集。需要注意的是,終止索引標識的項不包括在切片內。切片提供了一個相關數組的動態窗口。 切片是可索引的,并且可以由?`len()`?函數獲取長度。 給定項的切片索引可能比相關數組的相同元素的索引小。和數組不同的是,切片的長度可以在運行時修改,最小為 0 最大為相關數組的長度:切片是一個?**長度可變的數組**。 切片提供了計算容量的函數?`cap()`?可以測量切片最長可以達到多少:它等于切片的長度 + 數組除切片之外的長度。如果 s 是一個切片,`cap(s)`?就是從?`s[0]`?到數組末尾的數組長度。切片的長度永遠不會超過它的容量,所以對于 切片 s 來說該不等式永遠成立:`0 <= len(s) <= cap(s)`。 多個切片如果表示同一個數組的片段,它們可以共享數據;因此一個切片和相關數組的其他切片是共享存儲的,相反,不同的數組總是代表不同的存儲。數組實際上是切片的構建塊。 **優點**?因為切片是引用,所以它們不需要使用額外的內存并且比使用數組更有效率,所以在 Go 代碼中 切片比數組更常用。 聲明切片的格式是:?`var identifier []type`(不需要說明長度)。 一個切片在未初始化之前默認為 nil,長度為 0。 切片的初始化格式是:`var slice1 []type = arr1[start:end]`。 這表示 slice1 是由數組 arr1 從 start 索引到?`end-1`?索引之間的元素構成的子集(切分數組,start:end 被稱為 slice 表達式)。所以?`slice1[0]`?就等于?`arr1[start]`。這可以在 arr1 被填充前就定義好。 如果某個人寫:`var slice1 []type = arr1[:]`?那么 slice1 就等于完整的 arr1 數組(所以這種表示方式是`arr1[0:len(arr1)]`?的一種縮寫)。另外一種表述方式是:`slice1 = &arr1`。 `arr1[2:]`?和?`arr1[2:len(arr1)]`?相同,都包含了數組從第二個到最后的所有元素。 `arr1[:3]`?和?`arr1[0:3]`?相同,包含了從第一個到第三個元素(不包括第三個)。 如果你想去掉 slice1 的最后一個元素,只要?`slice1 = slice1[:len(slice1)-1]`。 一個由數字 1、2、3 組成的切片可以這么生成:`s := [3]int{1,2,3}`?甚至更簡單的?`s := []int{1,2,3}`。 `s2 := s[:]`?是用切片組成的切片,擁有相同的元素,但是仍然指向相同的相關數組。 一個切片 s 可以這樣擴展到它的大小上限:`s = s[:cap(s)]`,如果再擴大的話就會導致運行時錯誤(參見第 7.7 節)。 對于每一個切片(包括 string),以下狀態總是成立的: ~~~ s == s[:i] + s[i:] // i是一個整數且: 0 <= i <= len(s) len(s) < cap(s) ~~~ 切片也可以用類似數組的方式初始化:`var x = []int{2, 3, 5, 7, 11}`。這樣就創建了一個長度為 5 的數組并且創建了一個相關切片。 切片在內存中的組織方式實際上是一個有 3 個域的結構體:指向相關數組的指針,切片 長度以及切片容量。下圖給出了一個長度為 2,容量為 4 的切片。 * `y[0] = 3`?且?`y[1] = 5`。 * 切片?`y[0:4]`?由 元素 3, 5, 7 和 11 組成。 [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/7.2_fig7.2.png?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/7.2_fig7.2.png?raw=true) 示例 7.7?[array_slices.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_7/array_slices.go) ~~~ package main import "fmt" func main() { var arr1 [6]int var slice1 []int = arr1[2:5] // item at index 5 not included! // load the array with integers: 0,1,2,3,4,5 for i := 0; i < len(arr1); i++ { arr1[i] = i } // print the slice for i := 0; i < len(slice1); i++ { fmt.Printf("Slice at %d is %d\n", i, slice1[i]) } fmt.Printf("The length of arr1 is %d\n", len(arr1)) fmt.Printf("The length of slice1 is %d\n", len(slice1)) fmt.Printf("The capacity of slice1 is %d\n", cap(slice1)) // grow the slice slice1 = slice1[0:4] for i := 0; i < len(slice1); i++ { fmt.Printf("Slice at %d is %d\n", i, slice1[i]) } fmt.Printf("The length of slice1 is %d\n", len(slice1)) fmt.Printf("The capacity of slice1 is %d\n", cap(slice1)) // grow the slice beyond capacity //slice1 = slice1[0:7 ] // panic: runtime error: slice bound out of range } ~~~ 輸出: ~~~ Slice at 0 is 2 Slice at 1 is 3 Slice at 2 is 4 The length of arr1 is 6 The length of slice1 is 3 The capacity of slice1 is 4 Slice at 0 is 2 Slice at 1 is 3 Slice at 2 is 4 Slice at 3 is 5 The length of slice1 is 4 The capacity of slice1 is 4 ~~~ 如果 s2 是一個 slice,你可以將 s2 向后移動一位?`s2 = s2[1:]`,但是末尾沒有移動。切片只能向后移動,`s2 = s2[-1:]`會導致編譯錯誤。切片不能被重新分片以獲取數組的前一個元素。 **注意**?絕對不要用指針指向 slice。切片本身已經是一個引用類型,所以它本身就是一個指針!! 問題 7.2: 給定切片?`b:= []byte{'g', 'o', 'l', 'a', 'n', 'g'}`,那么?`b[1:4]`、`b[:2]`、`b[2:]`?和?`b[:]`?分別是什么? ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md#722-將切片傳遞給函數)7.2.2 將切片傳遞給函數 如果你有一個函數需要對數組做操作,你可能總是需要把參數聲明為切片。當你調用該函數時,把數組分片,創建為一個 切片引用并傳遞給該函數。這里有一個計算數組元素和的方法: ~~~ func sum(a []int) int { s := 0 for i := 0; i < len(a); i++ { s += a[i] } return s } func main { var arr = [5]int{0, 1, 2, 3, 4} sum(arr[:]) } ~~~ ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md#723-用-make-創建一個切片)7.2.3 用 make() 創建一個切片 當相關數組還沒有定義時,我們可以使用 make() 函數來創建一個切片 同時創建好相關數組:`var slice1 []type = make([]type, len)`。 也可以簡寫為?`slice1 := make([]type, len)`,這里?`len`?是數組的長度并且也是?`slice`?的初始長度。 所以定義?`s2 := make([]int, 10)`,那么?`cap(s2) == len(s2) == 10`。 make 接受 2 個參數:元素的類型以及切片的元素個數。 如果你想創建一個 slice1,它不占用整個數組,而只是占用以 len 為個數個項,那么只要:`slice1 := make([]type, len, cap)`。 make 的使用方式是:`func make([]T, len, cap)`,其中 cap 是可選參數。 所以下面兩種方法可以生成相同的切片: ~~~ make([]int, 50, 100) new([100]int)[0:50] ~~~ 下圖描述了使用 make 方法生成的切片的內存結構:[![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/7.2_fig7.2.1.png?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/7.2_fig7.2.1.png?raw=true) 示例 7.8?[make_slice.go](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/examples/chapter_7/make_slice.go) ~~~ package main import "fmt" func main() { var slice1 []int = make([]int, 10) // load the array/slice: for i := 0; i < len(slice1); i++ { slice1[i] = 5 * i } // print the slice: for i := 0; i < len(slice1); i++ { fmt.Printf("Slice at %d is %d\n", i, slice1[i]) } fmt.Printf("\nThe length of slice1 is %d\n", len(slice1)) fmt.Printf("The capacity of slice1 is %d\n", cap(slice1)) } ~~~ 輸出: ~~~ Slice at 0 is 0 Slice at 1 is 5 Slice at 2 is 10 Slice at 3 is 15 Slice at 4 is 20 Slice at 5 is 25 Slice at 6 is 30 Slice at 7 is 35 Slice at 8 is 40 Slice at 9 is 45 The length of slice1 is 10 The capacity of slice1 is 10 ~~~ 因為字符串是純粹不可變的字節數組,它們也可以被切分成 切片。 練習 7.4: fobinacci_funcarray.go: 為練習 7.3 寫一個新的版本,主函數調用一個使用序列個數作為參數的函數,該函數返回一個大小為序列個數的 Fibonacci 切片。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md#724-new-和-make-的區別)7.2.4 new() 和 make() 的區別 看起來二者沒有什么區別,都在堆上分配內存,但是它們的行為不同,適用于不同的類型。 * new(T) 為每個新的類型T分配一片內存,初始化為 0 并且返回類型為*T的內存地址:這種方法?**返回一個指向類型為 T,值為 0 的地址的指針**,它適用于值類型如數組和結構體(參見第 10 章);它相當于?`&T{}`。 * make(T)?**返回一個類型為 T 的初始值**,它只適用于3種內建的引用類型:切片、map 和 channel(參見第 8 章,第 13 章)。 換言之,new 函數分配內存,make 函數初始化;下圖給出了區別: [![](https://github.com/Unknwon/the-way-to-go_ZH_CN/raw/master/images/7.3_fig7.3.png?raw=true)](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/images/7.3_fig7.3.png?raw=true) 在圖 7.3 的第一幅圖中: ~~~ var p *[]int = new([]int) // *p == nil; with len and cap 0 p := new([]int) ~~~ 在第二幅圖中,?`p := make([]int, 0)`?,切片 已經被初始化,但是指向一個空的數組。 以上兩種方式實用性都不高。下面的方法: ~~~ var v []int = make([]int, 10, 50) ~~~ 或者 ~~~ v := make([]int, 10, 50) ~~~ 這樣分配一個有 50 個 int 值的數組,并且創建了一個長度為 10,容量為 50 的 切片 v,該 切片 指向數組的前 10 個元素。 **問題 7.3**?給定?`s := make([]byte, 5)`,len(s) 和 cap(s) 分別是多少?`s = s[2:4]`,len(s) 和 cap(s) 又分別是多少? **問題 7.4**?假設?`s1 := []byte{'p', 'o', 'e', 'm'}`?且?`s2 := d[2:]`,s2 的值是多少?如果我們執行?`s2[1] == 't'`,s1 和 s2 現在的值又分配是多少? ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md#725-多維-切片)7.2.5 多維 切片 和數組一樣,切片通常也是一維的,但是也可以由一維組合成高維。通過分片的分片(或者切片的數組),長度可以任意動態變化,所以 Go 語言的多維切片可以任意切分。而且,內層的切片必須單獨分配(通過 make 函數)。 ## [](https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/07.2.md#726-bytes-包)7.2.6 bytes 包 類型?`[]byte`?的切片十分常見,Go 語言有一個 bytes 包專門用來解決這種類型的操作方法。 bytes 包和字符串包十分類似(參見第 4.7 節)。而且它還包含一個十分有用的類型 Buffer: ~~~ import "bytes" type Buffer struct { ... } ~~~ 這是一個長度可變的 bytes 的 buffer,提供 Read 和 Write 方法,因為讀寫長度未知的 bytes 最好使用 buffer。 Buffer 可以這樣定義:`var buffer bytes.Buffer`。 或者使用 new 獲得一個指針:`var r *bytes.Buffer = new(bytes.Buffer)`。 或者通過函數:`func NewBuffer(buf []byte) *Buffer`,創建一個 Buffer 對象并且用 buf 初始化好;NewBuffer 最好用在從 buf 讀取的時候使用。 **通過 buffer 串聯字符串** 類似于 Java 的 StringBuilder 類。 在下面的代碼段中,我們創建一個 buffer,通過?`buffer.WriteString(s)`?方法將字符串 s 追加到后面,最后再通過`buffer.String()`?方法轉換為 string: ~~~ var buffer bytes.Buffer for { if s, ok := getNextString(); ok { //method getNextString() not shown here buffer.WriteString(s) } else { break } } fmt.Print(buffer.String(), "\n") ~~~ 這種實現方式比使用?`+=`?要更節省內存和 CPU,尤其是要串聯的字符串數目特別多的時候。 **練習 7.5**?給定切片 sl,將一個?`[]byte`?數組追加到 sl 后面。寫一個函數?`Append(slice, data []byte) []byte`,該函數在 sl 不能存儲更多數據的時候自動擴容。 **練習 7.6**?把一個緩存 buf 分片成兩個 切片:第一個是前 n 個 bytes,后一個是剩余的,用一行代碼實現。
                  <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>

                              哎呀哎呀视频在线观看