2016-08-15 91 views
0

去切片問題,請檢查下面,並評論如果我失去了一些東西。Go Slice - [:n]和[n:]之間的差異

import "fmt" 
    func main() { 
     s := []int{2, 3, 5, 7, 11, 13} 
     s = s[1:] 
     fmt.Println(s) 
     s = s[2:] 
     fmt.Println(s) 
     s = s[5:] 
     fmt.Println(s) 
    } 

輸出:上述

[3 5 7 11 13] [7 11 13] panic: runtime error: slice bounds out of range

很有意義。

func main() { 
     s := []int{2, 3, 5, 7, 11, 13} 
     s = s[:1] 
     fmt.Println(s) 
     s = s[:2] 
     fmt.Println(s) 
     s = s[:5] 
     fmt.Println(s) 
    } 

輸出:

[2] [2 3] [2 3 5 7 11]

如果這還從s = S得到數組出界恐慌[:2]?

+0

我的問題是w.r.t賦值,當我們執行s = s [:n]時,我的思維正在被新片覆蓋,舊片陣列中\ slice實際上已經丟失,不再存在。但相反,我繼續對已經切片並切片的原始數組進行切片,這看起來與Java不同。 –

回答

2

在Go中進行Subslicing操作可以讓您在切片末尾切片,只要它仍在底層陣列的容量範圍內即可。您不能在之前切片該切片的開始,但只要您不超過最後分配的索引,就可以切片。

舉個例子,s[3:]然後s[:3]作品,但s[4:]然後s[:4]會產生恐慌,因爲你通過對底層數組,其中僅分配了指標0-5的7請求指標4。

這有點奇怪,但它確實可以讓你通過簡單地做slice = slice[:cap(slice)]來最大化任何切片。

https://play.golang.org/p/Gq5xoXc3Vd

language specification annotes此,順便說一句。我在下面解釋了你正在使用的簡單切片符號(有一個替代方案也指定了新切片的最大索引)。

對於字符串,數組,指向數組的指針或切片a,主表達式a[low : high]構造子字符串或切片。 如果0 < =低< =高< =上限(a), ,則指數在範圍內,否則它們超出範圍。

+0

謝謝,我的問題是w.r.t賦值,當我們執行s = s [:n]時,我的思維正在被舊的數組\片切實丟失的新片覆蓋。這對我來說似乎有點不直觀。 –

+0

啊,不,相同的底層陣列。基本上,分片只是一個3字結構,帶有一個指向底層數組的指針,一個整數長度和一個整數容量。當您進行子切換時,您可以根據需要更改該切片「標題」(或創建一個新的切片)並更新字段。當你執行's = s [:n]'時,所做的只是將片頭的「長度」值改爲'n'。仍然指向相同的底層陣列,仍具有相同的容量,因此您可以再次將其擴展到該容量。 – Kaedys

+0

如果你想複製底層數組(即有一個指向完全不同數組的新切片,但其中有相同的數據),則需要手動執行,按索引索引或使用內置['copy()'](https://golang.org/pkg/builtin/#copy)函數,它可以對slice進行深層複製。 **編輯:**只能深入複製到數組級別。如果你的數組存儲指針,那些將不會被深度複製。 – Kaedys

0

我只是想閱讀官方博客之後分享我對這個想法:https://blog.golang.org/slices

這裏是sliceHeader在Golang的博客:

type sliceHeader struct { 
    Length  int 
    ZerothElement *byte 
} 

現在你宣佈你的切片:

s := []int{2, 3, 5, 7, 11, 13} 

我相信這樣做:

var array [6]int 
slice := sliceHeader { 
    Length:  6, 
    ZerothElement: &array[0], 
} 

這樣做:s = s[:2],您可以有效地改變了sliceHeader的長度從6比2,讓您的sliceHeader看起來就像這樣:

slice := sliceHeader { 
    Length:  2, 
    ZerothElement: &array[0], 
} 

注意,ZerothElement仍然指向同一個地方在記憶中。所以我們可以通過再次改變長度來將切片延伸回原始形式s = s[:6]

現在,讓我們說你沒有做s = s[:2],而是做了s = s[2:],你有什麼有效的行爲,即是從長度減去2和ZerothElement兩個指數前進換檔,造成的sliceHeader隱藏前兩個元素:

slice := sliceHeader { 
    Length:  4, 
    ZerothElement: &array[2], 
} 

此時,您無法將切片恢復到其原始形式,因爲無法將切片延伸到ZerothElement之外。好吧,假設你可以訪問ZerothElement之前的任何元素呢?然後我們的切片變得未定義,因爲它可能是array[0...4],array[1...5]array[2...6]

所以是的,這就是爲什麼我認爲[n:]和[:n]行爲不同。

相關問題