slice是golang提供的一個很好的符合類型。既支持數據動態擴展,又能隨機訪問,使數據保持很好的局部性。但是slice有一個性能可能導致數據的一致性和預期不一致,就是它會按需爲slice收集內存。參考這段代碼:
=========================================
package main
import "fmt"
func main() {
var data = []string{"one", "", "three"} //what's the differenct to assign underlying or not
var data2 = [...]string{"one", "", "three"} //what's the differenct to assign underlying or not
intTest := 3
fmt.Printf("intTest %%T after append is %T \n", intTest)
fmt.Printf("intTest %%p after append is %p \n", intTest)
fmt.Printf("data %%v is %v \n", data)
fmt.Printf("data %%q is %q \n", data)
out := data[:0]
for _, s := range data {
if s != "" {
out = append(out, s)
}
}
fmt.Printf("data %%v after append is %v \n", data)
fmt.Printf("data %%q after append is %q \n", data)
fmt.Printf("data %%s after append is %s \n", data)
fmt.Printf("data %%T after append is %T \n", data)
fmt.Printf("data %%p after append is %p \n", data)
fmt.Printf("&data %%p after append is %p \n", &data)
fmt.Printf("data2 %%T after append is %T \n", data2)
fmt.Printf("data2 %%p after append is %p \n", data2)
fmt.Printf("&data2 %%p after append is %p \n", &data2)
fmt.Printf("&data2 %%d after append is %d \n", &data2)
fmt.Printf("out %%v after append is %v \n", out)
fmt.Printf("out %%q after append is %q \n", out)
out2 := append(data[:0], "a", "b", "c", "d")
fmt.Printf("data %%v after append is %v \n", data)
fmt.Printf("data %%q after append is %q \n", data)
fmt.Printf("out2 %%v after append is %v \n", out2)
fmt.Printf("out2 %%q after append is %q \n", out2)
out3 := append(data[:0], "a", "b", "c")
fmt.Printf("data %%v after append is %v \n", data)
fmt.Printf("data %%q after append is %q \n", data)
fmt.Printf("out3 %%v after append is %v \n", out3)
fmt.Printf("out3 %%q after append is %q \n", out3)
}
=========================================
output:
=========================================
- intTest %T after append is int
- intTest %p after append is %!p(int=3)
- data %v is [one three]
- data %q is ["one" "" "three"]
- data %v after append is [one three three]
- data %q after append is ["one" "three" "three"]
- data %s after append is [one three three]
- data %T after append is []string
- data %p after append is 0xc420062150
- &data %p after append is 0xc42007a020
- data2 %T after append is [3]string
- data2 %p after append is %!p([3]string=[one three])
- &data2 %p after append is 0xc420062180
- &data2 %d after append is &[%!d(string=one) %!d(string=) %!d(string=three)]
- out %v after append is [one three]
- out %q after append is ["one" "three"]
- data %v after append is [one three three]
- data %q after append is ["one" "three" "three"]
- out2 %v after append is [a b c d]
- out2 %q after append is ["a" "b" "c" "d"]
- data %v after append is [a b c]
- data %q after append is ["a" "b" "c"]
- out3 %v after append is [a b c]
- out3 %q after append is ["a" "b" "c"]
=========================================
從輸出裏我們可以得出兩條結論:
1. 對比第17行(append數據長度超出capacity)和第21行的輸出(append數據長度未超出capacity),slice在容量足夠的時候修改已有的array,在容量不夠的時候才realloc內存基於新的內存建立array
2. 對比第12行和9行,golang是強類型的,%p只對引用內型或者取地址有效
3. 對比第9行和第10行,golang對slice和&slice的值定義了不同的語義