內(nèi)置append()函數(shù)能夠在切片末尾位置添加新的項,假設(shè)要在切片的前面或者中間某位置插入特定項,可以這樣實現(xiàn)
看下代碼:
package main
import "fmt"
func main() {
s := []string{"M","N","O","P","Q","R"}
x := InsertStringSliceCopy(s,[]string{"a","b","c"},0)
y := InsertStringSliceCopy(s,[]string{"a","b","c"},3)
fmt.Printf("%v\n%v\n",x,y)
}
func InsertStringSliceCopy(slice,insertion []string,index int)[]string {
result := make([]string,len(slice) + len(insertion))
at := copy(result,slice[:index])
at += copy(result[at:],insertion)
copy(result[at:],slice[index:])
fmt.Printf("%6T\n",at)
return result
}
運行結(jié)果:
自定義的InsertStringSliceCopy()函數(shù)可以實現(xiàn)在切片相應(yīng)的位置插入項
此外InsertStringSliceCopy()函數(shù)中打印類變量at的類型,可知內(nèi)置函數(shù)copy()在實現(xiàn)復(fù)制功能的時候會有一個int的返回值
補充:go學(xué)習(xí)備忘錄 - 切片中間插入元素
1. 通過鏈?zhǔn)絘ppend 實現(xiàn)
將多個append操作組合起來,實現(xiàn)在切片中間插入元素:
var a []int
a = append(a[:i], append([]int{1}, a[i:]...)...) // 在第i個位置插入1
a = append(a[:i], append([]int{1,2,3}, a[i:]...)...) // 在第i個位置插入切片
每個鏈?zhǔn)讲僮髦械牡诙€append調(diào)用都會創(chuàng)建一個臨時切片,并將a[i:]的內(nèi)容復(fù)制到新創(chuàng)建的切片中,然后將臨時創(chuàng)建的切片再追加到a[:i]。
2. 通過copy + append 實現(xiàn)
通過 copy和append組合 可以避免創(chuàng)建中間的臨時切片
a = append(a, 0) // 切片擴展1個空間
copy(a[i+1:], a[i:]) // a[i:]向后移動1個位置
a[i] = x // 設(shè)置新添加的元素
用copy和append組合在中間位置插入多個元素(也就是插入一個切片):
a = append(a, x...) // 為x切片擴展足夠的空間
copy(a[i+len(x):], a[i:]) // a[i:]向后移動len(x)個位置
copy(a[i:], x) // 復(fù)制新添加的切片
注:append本質(zhì)是用于追加元素而不是擴展容量,擴展切片容量只是append的一個副作用。
補充:Go語言中切片作為函數(shù)參數(shù),函數(shù)中使用append添加元素
切片作為函數(shù),通過append添加元素,有可能會更改地址:
1)添加的數(shù)據(jù)元素長度超過切片參數(shù)的容量,則會另開辟空間,重新分配底層數(shù)組,并復(fù)制數(shù)據(jù)。函數(shù)中的此切片與原切片地址不同; 此切片指向新開辟的內(nèi)存。函數(shù)運行結(jié)束,內(nèi)存釋放,不會影響元切片的內(nèi)容。
2)否則原切片與函數(shù)中的切片指向同一地址。會影響切片的內(nèi)容。
3)切片名本身就是一個指針(內(nèi)容保存指向切片的首地址)
代碼測試:
package main
import "fmt"
func main01() {
s := make([]int, 3, 5)
s[2] = 8888
fmt.Printf("原地址:%p", s)
s = append(s, 12)
fmt.Printf("\n添加數(shù)據(jù)之后的地址:%p", s)
/*
append添加元素,容量足夠,則在原基礎(chǔ)之上添加數(shù)據(jù),地址不會發(fā)生改變
輸出:
原地址:0xc04207e030
添加數(shù)據(jù)之后的地址:0xc04207e030
*/
}
func main02() {
s := make([]int, 3)
s[2] = 666
fmt.Printf("append添加數(shù)據(jù)之前的地址:%p", s)
s = append(s, 888)
fmt.Printf("\nappend添加數(shù)據(jù)之后的地址:%p", s)
/*
append添加數(shù)據(jù),容量不夠,則另行開辟空間,切片地址發(fā)生變化
輸出:
append添加數(shù)據(jù)之前的地址:0xc04200e2c0
append添加數(shù)據(jù)之后的地址:0xc04200a2d0
*/
}
func main() {
/*
copy(目的切片,原切片):切片拷貝
注意事項:目的切片要有足夠的空間,如果沒有空間(切片為空或者指向0x0),不能進行拷貝
若目的切片容量不足,只拷貝部分(目的切片長度的部分)
返回值為拷貝成功的切片數(shù)量
*/
s := make([]int, 3)
s[0] = 0
s[1] = 111
s[2] = 666
//var s1 []int = []int{5: 333}
//n:=copy(s,s1)
s1 := make([]int, 1, 2)
n := copy(s1, s)
fmt.Printf("原切片s的地址是:%p", s)
fmt.Printf("\n拷貝之后的切片s1的地址是:%p,數(shù)量:%d", s1, n)
fmt.Println(s1)
}
補充說明:
數(shù)組和slice之間有著緊密的聯(lián)系。一個slice是一個輕量級的數(shù)據(jù)結(jié)構(gòu),提供了訪問數(shù)組子序列(或者全部)元素的功能,而且slice的底層確實引用一個數(shù)組對象。一個slice由三個部分構(gòu)成:指針、長度和容量。指針指向第一個slice元素對應(yīng)的底層數(shù)組元素的地址,要注意的是slice的第一個元素并不一定就是數(shù)組的第一個元素。
切片并不是數(shù)組或數(shù)組指針,它通過內(nèi)部指針和相關(guān)屬性引⽤數(shù)組⽚段,以實現(xiàn)變⻓⽅案。
slice并不是真正意義上的動態(tài)數(shù)組,而是一個引用類型。slice總是指向一個底層array,slice的聲明也可以像array一樣,只是不需要長度。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
您可能感興趣的文章:- go語言求任意類型切片的長度操作
- 如何在Go中使用切片容量和長度
- golang中切片copy復(fù)制和等號復(fù)制的區(qū)別介紹
- go語言中切片與內(nèi)存復(fù)制 memcpy 的實現(xiàn)操作
- go語言中的二維切片賦值
- go語言中切片的長度和容量的區(qū)別