注:本文是對 golang-101-hacks 中文翻譯。
創(chuàng)新互聯(lián)建站是一家專注網(wǎng)站建設(shè)、網(wǎng)絡(luò)營銷策劃、小程序設(shè)計、電子商務(wù)建設(shè)、網(wǎng)絡(luò)推廣、移動互聯(lián)開發(fā)、研究、服務(wù)為一體的技術(shù)型公司。公司成立十年以來,已經(jīng)為上1000+成都iso認證各業(yè)的企業(yè)公司提供互聯(lián)網(wǎng)服務(wù)。現(xiàn)在,服務(wù)的上1000+客戶與我們一路同行,見證我們的成長;未來,我們一起分享成功的喜悅。
在Go語言中,函數(shù)參數(shù)是值傳遞。使用slice作為函數(shù)參數(shù)時,函數(shù)獲取到的是slice的副本:一個指針,指向底層數(shù)組的起始地址,同時帶有slice的長度和容量。既然各位熟知數(shù)據(jù)存儲的內(nèi)存的地址,現(xiàn)在可以對切片數(shù)據(jù)進行修改。讓我們看看下面的例子:
In Go, the function parameters are passed by value. With respect to use slice as a function argument, that means the function will get the copies of the slice: a pointer which points to the starting address of the underlying array, accompanied by the length and capacity of the slice. Oh boy! Since you know the address of the memory which is used to store the data, you can tweak the slice now. Let's see the following example:
運行結(jié)果如下
由此可見,執(zhí)行modifyValue函數(shù),切片s的元素發(fā)生了變化。盡管modifyValue函數(shù)只是操作slice的副本,但是任然改變了切片的數(shù)據(jù)元素,看另一個例子:
You can see, after running modifyValue function, the content of slice s is changed. Although the modifyValue function just gets a copy of the memory address of slice's underlying array, it is enough!
See another example:
The result is like this:
而這一次,addValue函數(shù)并沒有修改main函數(shù)中的切片s的元素。這是因為它只是操作切片s的副本,而不是切片s本身。所以如果真的想讓函數(shù)改變切片的內(nèi)容,可以傳遞切片的地址:
This time, the addValue function doesn't take effect on the s slice in main function. That's because it just manipulate the copy of the s, not the "real" s.
So if you really want the function to change the content of a slice, you can pass the address of the slice:
運行結(jié)果如下
定義一個切片,然后讓切片去引用一個已經(jīng)創(chuàng)建好的數(shù)組?;菊Z法如下:
索引1:切片引用的起始元素位
索引2:切片只引用該元素位之前的元素
例程如下:
在該方法中,我們未指定容量cap,這里的值為5是系統(tǒng)定義的。
在方法一中,可以用arr數(shù)組名來操控數(shù)組中的元素,也可以通過slice切片來操控數(shù)組中的元素。切片是直接引用數(shù)組,數(shù)組是事先存在的,程序員是可見的。
通過 make 來創(chuàng)建切片,基本語法如下:
make函數(shù)第三個參數(shù)cap即容量是可選的,如果一定要自己注明的話,要注意保證cap≥len。
用該方法可以 指定切片的大小(len)和容量(cap)
例程如下:
由于未賦值系統(tǒng)默認將元素值置為0,即:
數(shù)值類型數(shù)組:????默認值為 0
字符串數(shù)組:? ? ? ?默認值為 ""
bool數(shù)組:? ? ? ? ? ?默認值為 false
在方法二中,通過make方式創(chuàng)建的切片對應(yīng)的數(shù)組是由make底層維護,對外不可見,即只能通過slice去訪問各個元素。
定義一個切片,直接就指定具體數(shù)組,使用原理類似于make的方式。
例程如下:
? 再來分析一下golang中的切片slice底層的實現(xiàn)細節(jié)。
slice通過數(shù)組實現(xiàn),類似一個結(jié)構(gòu)體,其中一個字段保存的是底層數(shù)組的地址,還有長度(len) 和 容量(cap)兩個字段。
? ? 我們都知道,結(jié)構(gòu)體作為函數(shù)參數(shù)時是值拷貝,同理,實際上slice作為函數(shù)參數(shù)時也是值拷貝,在函數(shù)中對slice的修改是通過slice中保存的地址對底層數(shù)組進行修改,所以函數(shù)外的silce看起來被改變了。
? ? 當需要對slice做插入和刪除時(如:append操作),由于需要更改slice結(jié)構(gòu)體中的長度字段,值拷貝就行不通了,需要傳slice本身在內(nèi)存中的地址。
看一個值傳遞的例子:
```
package main
import "fmt"
func processSlice(x []int) {
x = append(x, 6)
}
func main() {
var numbers = []int{1, 2, 3, 4, 5}
processSlice(numbers)
for _, v := range(numbers) {
fmt.Println(v)
}
}
```
1 2 3 4 5
再看一個指針傳遞的例子:
```
package main
import "fmt"
func processSlice(x *[]int) {
*x = append(*x, 6)
}
func main() {
var numbers = []int{1, 2, 3, 4, 5}
processSlice(numbers)
for _, v := range(numbers) {
fmt.Println(v)
}
}
```
1 2 3 4 5 6
slice for 循環(huán)中刪除元素
方法1:
```
chars:=[]string{"a","a","b"}
fori:=0;ilen(chars);i++{
if chars[i]=="a" {
chars=append(chars[:i],chars[i+1:]...)
i--// form the remove item index to start iterate next item
}
}
fmt.Printf("%+v",chars)
```
方式2:
```
p := []int{1, -13, 9, 6, -21, 125}
j := 0
for _, n := range p {
if n 0 {
? ? p[j] = n? ?//刪除小于零的元素
? ? j++
}
}
```
不改原slice
```
p := []int{1, -13, 9, 6, -21, 125}
j := 0
q := make([]int, len(p))
for _, n := range p {
if n 0 {
q[j] = n? ?//刪除小于零的元素
j++
}
}
q = q[:j]
```