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

                # 3.2 切片 在go中,你一般很少直接使用數組。相反,你會使用切片。切片是一個輕量級的結構體封裝,這個結構體被封裝后,代表一個數組的一部分。這里指出了一些創建切片的方式,并指出我們以后會在何時使用這些方式。 第一種方式和我們創建一個數組時有點細微的變化: `scores := []int{1,4,293,4,9}` 和聲明數組不同的是,聲明切片不需要在方括號中指定其大小。理解2中不同的方式創建切片,下面使用另外一種方式創建切片,這里使用`make`: `scores := make([]int, 10)` 我們使用`make`,沒有使用`new`,是因為創建一個切片不僅僅是分配一段內存(`new`只能分配一段內存)。需要特別指出的是,我們需要為底層數組分配內存,并且也要初始化這個切片。在上面的例子中,我們初始化了一個長度和容量都是10的切片。長度表示切片的長度,容量表示底層數組的大小。在使用`make`創建切片時,我們可以分別的指定長度和容量大小: `scores := make([]int, 0, 10)` 上面創建了一個長度為0但是容量為10的切片。(如果你留意過,你會發現`make`和`len`實現了重載。go語言的一些特性會讓你有點失望,因為有些特性是沒有暴露出來給開發者使用。) 要更好的理解切片長度和容量之間的相互作用,讓我們看下面的例子: ```go func main() { scores := make([]int, 0, 10) scores[5] = 9033 fmt.Println(scores) } ``` 上面的例子不能運行。為什么?因為我們創建的切片長度是0。是的,這個底層的數組有10個元素。但是為了訪問切片元素,我們需要明確的擴展切片。一種擴展切片的方式是使用`append`: ```go func main() { scores := make([]int, 0, 10) scores = append(scores, 5) fmt.Println(scores) // 打印:[5] } ``` 但是這改變為了我們之前代碼的意圖。當往一個長度為0的切片上添加元素時,這個元素會被賦值給切片的第一個元素。不管出于什么原因,那段不能運行的代碼想給切片的第6個元素賦值。為了到達這個目的,我們可以再切分一直我們的切片: ```go func main() { scores := make([]int, 0, 10) scores = scores[0:6] scores[5] = 9033 fmt.Println(scores) } ``` 調整切片的大小上限是多少?這個上限就是切片的容量大小,在上面的例子中,上限是10。你也許會認為,這實際沒有解決定長數組的問題。事實證明,`append`比較特殊。如果底層的數組已經達到上限,`append`會重新創建一個更大的數組,并將所有的值復制過去(這就是動態數組的工作原理,例如php、python、ruby和javascript等等)。這就是為什么我們在上面的例子中使用`append`。我們必須將`append`返回的值重新賦予給`scores`變量:如果原始切片沒有更多的空間時,`append`可能會創建一個新值。 如果我告訴你go擴展數組使用的是2倍算法(2x algorithm)。你能猜出下面代碼將輸出什么嗎? ```go func main() { scores := make([]int, 0, 5) c := cap(scores) fmt.Println(c) for i := 0; i < 25; i++ { scores = append(scores, i) // 如果容量已經改變,go為了容下這些新數據,不得不增長數組的長度 if cap(scores) != c { c = cap(scores) fmt.Println(c) } } } ``` 切片`scores`的初始容量是5。但是為了容納20個元素,切片的容量必須擴展3次,分別是10、20和40。 作為最后一個例子,思考一下: ```go func main() { scores := make([]int, 5) scores = append(scores, 9332) fmt.Println(scores) } ``` 當面的代碼輸出是`[0, 0, 0, 0, 0, 9332]`。也許你認為應該是`[9332, 0, 0, 0, 0]`。對人類來說,這似乎更合乎邏輯。但是對于編譯器來說,你是要告訴它往一個已經擁有5個元素的切片添加一個值。 最后,這里提供了4種常用的方式去初始化一個切片: ```go names := []string{"leto", "jessica", "paul"} checks := make([]bool, 10) var names []string scores := make([]int, 0, 20) ``` 你該使用哪一個?第一種你不需要太多的說明。但是使用這種方式你得提前知道你想往數組存放的值。 第二種方式在你想往切片的特定位置寫入一個值時很有用,例如: ```go func extractPowers(saiyans []*Saiyans) []int { powers := make([]int, len(saiyans)) for index, saiyan := range saiyans { powers[index] = saiyan.Power } return powers } ``` 第三種方式會返回一個空切片,一般和`append`一起使用,此時切片的元素數量是未知的。 最后一種方式可以讓我們指定切片的初始容量。當我們大概知道需要多少元素時很有用。即使你知道元素的個數,`append`也能被使用,這主要取決于個人喜好: ```go func extractPowers(saiyans []*Saiyans) []int { powers := make([]int, 0, len(saiyans)) for _, saiyan := range saiyans { powers = append(powers, saiyan.Power) } return powers } ``` 切片作為一個數組的封裝是一個非常有用的概念。很多語言都有類似的概念。javascript和ruby的數組都有一個`slice`方法。你也可以在ruby中通過`[START..END]`得到一個切片,或者在python中通過`[START:END]`得到一個切片。然而,在一些語言中,切片確實是從原始數組拷貝而來的新數組。如果我們使用`ruby`,下面代碼將輸出什么? ```go scores = [1,2,3,4,5] slice = scores[2..4] slice[0] = 999 puts scores ``` 答案是`[1, 2, 3, 4, 5]`。因為切片`slice`是由值拷貝組成的一個全新數組。現在,同等情況下看go: ```go scores := []int{1,2,3,4,5} slice := scores[2:4] slice[0] = 999 fmt.Println(scores) ``` 輸出是`[1, 2, 999, 4, 5]`。 這會如何改變你的代碼。例如,很多函數需要一個位置參數。在javascript中,如你我們想在前五個字符后查找一個字符串中的第一個空白符(對,切片也當字符串處理),我們可以這樣寫: ```javascript haystack = "the spice must flow"; console.log(haystack.indexOf(" ", 5)); ``` 在go中,我們使用切片: `strings.Index(haystack[5:], " ")` 從上面例子中,我們可以看出`[X:]`表示`X`到結尾的一種縮寫。而`[:X]`是開始到`X`的一種縮寫。不像其他語言,go不支持負值索引。如果我們想要切片所有元素,但除了最后一個,我們可以這樣寫: ```go scores := []int{1, 2, 3, 4, 5} scores = scores[:len(scores)-1] ``` 上述是一種從一個亂序的切片中去除一個值的有效方法。 ```go func main() { scores := []int{1, 2, 3, 4, 5} scores = removeAtIndex(scores, 2) fmt.Println(scores) } func removeAtIndex(source []int, index int) []int { lastIndex := len(source) - 1 //swap the last value and the value we want to remove source[index], source[lastIndex] = source[lastIndex], source[index] return source[:lastIndex] } ``` 最后,我們已經學習了切片,我們來學習一下另外一個常用的內置函數:`copy`。`copy`是眾多函數中重點顯示出切片如何改變我們代碼方式的函數之一。正常情況下,拷貝一個數組到另外一個數組的方法需要5個參數:`source`,`sourceStart`,`count`,`destination`和`destinationStart`。但是在切片中,我們只需要2個參數: ```go import ( "fmt" "math/rand" "sort" ) func main() { scores := make([]int, 100) for i := 0; i < 100; i++ { scores[i] = int(rand.Int31n(1000)) } sort.Ints(scores) worst := make([]int, 5) copy(worst, scores[:5]) fmt.Println(worst) } ``` 花點時間研究上面的代碼。試著改變一些代碼。如果你使用`copy(worst[2:4], scores[:5])`方式去復制看看會發生什么,或者試著復制多于或者少于5個值到`worst`。 ## 鏈接
                  <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>

                              哎呀哎呀视频在线观看