Go語言切片是在項目中經常使用的,在當前實例中會實現切片的賦值、賦值、追加以及在函數中通過值傳遞、引用傳遞的方式來修改切片值
package main
import "fmt"
func main() {
arrStr := [...]string{"java", "c","c++","python","c#","basic"}
sliceStr := arrStr[1:4:5] //下標一表示起始位置,下標二表示結束位置(不包含該位置元素),下標三表示cap容量 cap=len+1,容量可以設置大於len+1
fmt.Println("len(arrStr),cap(arrStr)", len(arrStr), cap(arrStr))
fmt.Println(arrStr)
fmt.Println("len(sliceStr),cap(sliceStr)", len(sliceStr), cap(sliceStr))
fmt.Println(sliceStr)
sliceStr[0] = "Go"
fmt.Println("after assigning slice, arrStr:")
sliceStr = append(sliceStr, "ruby")
fmt.Println(arrStr) //不超容量重新賦值後之前的數組會跟着改變
fmt.Println("len(sliceStr),cap(sliceStr)", len(sliceStr), cap(sliceStr))
fmt.Println(sliceStr)
sliceStr2 := arrStr[1:4]
fmt.Println("after assigning slice again")
sliceStr2 = append(sliceStr2, "ruby", "php", "javascript", "pl-sql")
fmt.Println(arrStr) //超容量重新賦值後之前的數組不會跟着改變
fmt.Println("len(sliceStr2),cap(sliceStr2)", len(sliceStr2), cap(sliceStr2))
fmt.Println(sliceStr2)
sliceStr3 := []string{"are","you","ok"}
var sliceStr4 = make([]string ,3)
copy(sliceStr4, sliceStr3) //copy會複製原有切片的值,修改時不影響原有元素。
var sliceStr5 = make([]string,5,10)
sliceStr4[0] = "how"
sliceStr4[1] = "are"
sliceStr4 = append(sliceStr4, "you")
sliceStr5 = sliceStr3[0:3]
sliceStr5 = append(sliceStr5, "do","not")
fmt.Println(sliceStr3)
fmt.Println(sliceStr4)
fmt.Println("before changing, sliceStr5:")
fmt.Println(sliceStr5)
changeSlice(sliceStr5) //切片是引用類型,在函數中改變內容的話,在函數外部能看到已經生效了。
fmt.Println("after changing sliceStr5:")
fmt.Println(sliceStr5)
languages := []string{"C","C++","Java","Go","PHP","Python","Ruby"}
already := languages[:len(languages)-2]
//這種賦值方法可以保證儘快地將languages數組做垃圾回收操作
var newAlready = make([]string, len(already)) //先聲明同樣大小的切片
copy(newAlready, already) //生成一個切片的副本,原始數組就可以儘快被垃圾回收
fmt.Println("newAlready:",newAlready)
other := []string{"Object-C","Swift", "Erlang"}
newAlready = append(newAlready, other...) //追加切片的正確寫法
fmt.Println("after append other slice, newAlready:", newAlready)
//使用可變參數的函數來更改切片本身的值
change(other...)
fmt.Println("after changing, other:", other)
var other1 = make([]string, len(other))
copy(other1, other)
fmt.Printf("before change1(), pointer:%p,cap: %d,", other1, cap(other1)) //獲取切片的內存地址
fmt.Println("before change1(), other1:", other1)
change1(other1) //
fmt.Printf("after change1(), pointer:%p,cap: %d,len:%d,", other1, cap(other1), len(other1)) //這裏的地址仍然是以前的地址,所以修改有效,追加無效。
fmt.Println("after change1(), other1:", other1)
other1 = append(other1, "javascript")
fmt.Printf("before change2(), pointer:%p,cap: %d,len:%d,", other1, cap(other1), len(other1)) //獲取切片的內存地址
fmt.Println("before change2(), other1:", other1)
change2(&other1) //
fmt.Printf("after change2(), pointer:%p,cap: %d,", other1, cap(other1)) //這裏的地址仍然是以前的地址,所以修改有效,追加無效。
fmt.Println("after change2(), other1:", other1)
other1 = append(other1, "vb.net", "shell") //一旦超出原有長度,會將原有的容量翻倍
fmt.Printf(" pointer:%p,cap: %d,len:%d \n", other1, cap(other1), len(other1))
useAppend()
}
func changeSlice(strSlice []string) {
strSlice[4] = "something"
}
func change(s ...string) {
s[0] = "Basic"
s = append(s, "C#") //追加的元素不會在函數外部顯示
fmt.Println("inside changing(), s:", s)
}
/**
切片包含長度、容量和指向數組第零個元素的指針。
當切片傳遞給函數時,即使它通過值傳遞,指針變量也將引用相同的底層數組。
因此,當切片作爲參數傳遞給函數時,函數內所做的更改也會在函數外可見。讓我們寫一個程序來檢查這點。
*/
func change1(s []string) {
s[0] = "Sql"
fmt.Printf("before append(), pointer:%p,cap: %d \n", s, cap(s))
s = append(s, "C#") //append函數執行後,會導致s切片的地址發生變化,傳入的切片與現在的切片已經不同
fmt.Printf("inside change1(), pointer:%p,cap: %d,", s, cap(s))
fmt.Println("inside change1(), s:", s)
}
/**
傳入變量地址,將會在函數內外都修改生效
*/
func change2(s *[]string) {
(*s)[0] = "Oracle"
fmt.Printf("before append(), pointer:%p,cap: %d,len:%d, \n", *s, cap(*s), len(*s))
*s = append(*s, "C#") //append函數執行後,會導致s切片的地址發生變化,傳入的切片與現在的切片已經不同
fmt.Printf("inside change2(), pointer:%p,cap: %d,len:%d,", *s, cap(*s), len(*s))
fmt.Println("inside change2(), s:", *s)
}
func useAppend() {
var numbers []int
for i := 0; i < 10; i++ {
numbers = append(numbers, i)
fmt.Printf("len: %d cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)
}
}
運行結果:
len(arrStr),cap(arrStr) 6 6
[java c c++ python c# basic]
len(sliceStr),cap(sliceStr) 3 4
[c c++ python]
after assigning slice, arrStr:
[java Go c++ python ruby basic]
len(sliceStr),cap(sliceStr) 4 4
[Go c++ python ruby]
after assigning slice again
[java Go c++ python ruby basic]
len(sliceStr2),cap(sliceStr2) 7 10
[Go c++ python ruby php javascript pl-sql]
[are you ok]
[how are ok you]
before changing, sliceStr5:
[are you ok do not]
after changing sliceStr5:
[are you ok do something]
newAlready: [C C++ Java Go PHP]
after append other slice, newAlready: [C C++ Java Go PHP Object-C Swift Erlang]
inside changing(), s: [Basic Swift Erlang C#]
after changing, other: [Basic Swift Erlang]
before change1(), pointer:0xc0000641e0,cap: 3,before change1(), other1: [Basic Swift Erlang]
before append(), pointer:0xc0000641e0,cap: 3
inside change1(), pointer:0xc0000703c0,cap: 6,inside change1(), s: [Sql Swift Erlang C#]
after change1(), pointer:0xc0000641e0,cap: 3,len:3,after change1(), other1: [Sql Swift Erlang]
before change2(), pointer:0xc000070420,cap: 6,len:4,before change2(), other1: [Sql Swift Erlang javascript]
before append(), pointer:0xc000070420,cap: 6,len:4,
inside change2(), pointer:0xc000070420,cap: 6,len:5,inside change2(), s: [Oracle Swift Erlang javascript C#]
after change2(), pointer:0xc000070420,cap: 6,after change2(), other1: [Oracle Swift Erlang javascript C#]
pointer:0xc00007c0c0,cap: 12,len:7
len: 1 cap: 1 pointer: 0xc00001c140
len: 2 cap: 2 pointer: 0xc00001c160
len: 3 cap: 4 pointer: 0xc0000142e0
len: 4 cap: 4 pointer: 0xc0000142e0
len: 5 cap: 8 pointer: 0xc000018100
len: 6 cap: 8 pointer: 0xc000018100
len: 7 cap: 8 pointer: 0xc000018100
len: 8 cap: 8 pointer: 0xc000018100
len: 9 cap: 16 pointer: 0xc00006e100
len: 10 cap: 16 pointer: 0xc00006e100