slice
package main import "fmt" func main() { /* slice :拥有相同类型元素的可变长的序列。 通常写成 []T,T是元素类型。 slice和数组的关联:slice是一种轻量级的数据结构,可以用来访问数组的部分或者全部元素 ,而这个数组成为slice的底层数组。一个底层数组可以对应多个slice slice三个属性:指针、长度、容量 1 指针:指向数组的第一个可以从slice中访问的元素,并不一定是数组的第一个元素 2 长度:slice中元素的个数,不能超过容量 3 容量:从slice的起始元素到底层数组的最后一个元素间元素的个数 定义:s[i,j] s可以使数组也可以是指向数组的指针 */ //定义一个底层数组 months:=[...]string{ 1:"January", 2:"February",3:"March", 4:"April", 5:"May",6:"June", 7:"July",8:"August",9:"September", 10:"October",11:"November",12:"December"} Q2:=months[4:7] //创建slice Q2,引用的是months数组的4,5,6 summer:=months[6:9] fmt.Println(Q2) // [April May June] 两个slice Q2 summer中都有June元素 fmt.Println(summer) // [June July August] //遍历 取 相同元素 for _,s:=range summer{ for _,q:=range Q2{ if s ==q{ /*%T 类型占位符 %v 值占位符 %d 整型占位符 %f 浮点型占位符 %c 字符占位符 %s 字符串占位符 %p指针占位符*/ fmt.Printf("%s appears in both\n", s) } } } scap:=cap(summer) fmt.Println(scap) //7 //如果slice的引用超过了被引用对象的容量,即 cap(s),则宕机;如果超过了备用用对象的长度,及len(s),那么最终slice回避原slicec长 //fmt.Println(summer[:20]) //宕机 超过了被引用对象的容量 endlessSummer:=summer[:5] fmt.Println(endlessSummer) // [June July August September October] 超过了备用用对象的长度 /* 注意 求字符串(string)子串操作 和 对字节slice([]byte)做slice 操作 是相似的,都协作x[m:n],都返回原始字节的一个子序列。 同时,他们的底层引用方式一样,所以两个操作都是消耗常量时间。 区别在于:如果x是字符串, x[m,n]返回的是一个字符串; 如果x是字节slice([]byte) ,x[m,n]返回的是 字节slice ([]byte) */ a:=[...]int{0,1,2,3,4,5} reverse(a[:]) // a[:] 标识引用了正式数组 fmt.Println(a) //[5 4 3 2 1 0] fmt.Printf("a格式:%T",a) // 将一个slice左移n个元素: 连续调用resverse三次 s:=[]int{0,1,2,3,4,5} //向左移动两个元素 reverse(s[:2]) reverse(s[2:]) reverse(s) fmt.Println(s) //[2 3 4 5 0 1] q:=[]int{0,1,2,3,4,5} //向右移动两个元素 reverse(q[4:]) reverse(q[:4]) reverse(q) fmt.Println(q) /* 注意 数组a slice s的初始化表达式区别。a是创建有固定长度的数组,s是创建指向数组的slice.。 slice也是按照顺序指定元素,也可以按照索引来指定元素,或两者结合 区别1 数组可以比较,slice无法比较,因此无法使用==来测试slic是否拥有相同的元素 标准库里给处理函数 bytes.Equal来比较两个字节slice([]byte).对于其他的 slice,我们必须自己写函数比较 区别2 slice的元素是间接的,如果底层数组的元素改变,sliced的元素原会改变 slice唯一允许的比较操作就是和nil作比较:例如 if summer == nil{......} slice 零值是 nil,值为nil的slice没有对应的底层数组,长度和容量都为零 */ // p:=[]int{1:1,0:0,3,4} 两者结合 报错.\slices.go:73:19: duplicate index in array literal: 1 p:=[]int{1:1,0:0,3:3,4} //两者结合 ok [0 1 0 3 4] fmt.Println(p) fmt.Printf("%T",p) /*内置函数 make 作用:创建一个具有制定元素类型、长度和容量的slice。容量可以省略,此时,slice的长度与容量相等 */ sm:=make([]int,8) println(sm) } func reverse(s []int) { // 初始值i,j:=0,len(s)-1 条件 i<j 表达式 i,j=i+1,j-1 for i,j:=0,len(s)-1;i<j;i,j=i+1,j-1{ s[i],s[j]=s[j],s[i] } }
append()函数
package main import "fmt" func main() { //rune类型 http://c.biancheng.net/view/18.html var runes []rune /*append函数 作用:将元素追加到slice后面 通常将append的调用结果再次复制给传入applend函数的slice,更新slice变量 对于任何函数,只要有可能改变slice的长度或者容量,或者使slice指向不同的底层数组 都需要更新slice变量 */ for _,r:=range "good"{ runes=append(runes,r) } fmt.Printf("%q\n",runes) //['g' 'o' 'o' 'd'] var x,y []int for i:=0;i<10;i++{ y=appendInt(x,i) fmt.Printf("%d cap=%d\t%v\n",i,cap(y),y) x=y } } //为[]int数组slice定义方法appendInt func appendInt(x []int,y int) []int { var z []int zlen := len(x)+1 //检查slice是否有足够容量来存储数组中的新元素 if zlen <= cap(x){ z=x[:zlen] //有足够的容量则 定义新的slice(底层数组未变),将元素y复制到新位置 }else{ /*slice已无空间,为他分配新的底层数组,不够长则创建一个足够长的新的底层数组来存储新元素, 增加两倍的目的是为了达到分摊线性复杂性 */ /*出于效率考录,新创建的数组容量会比实际容纳slice x slice y 所需的最小长度更大一i但。 在每次数组容量扩容是,通过扩展已被的容量来减少内存分配的次数,也可以保证追加一个元素消耗的 是固定时间 每次slice容量的改变都意味着一次底层数组重新分配和元素复制 */ zcap:=zlen if zcap<2*len(x){ zcap=2*len(x) } z=make([]int,zlen,zcap) //定义新的slice /*内置copy函数:为两个相同类型元素的slice复制元素 copy(目标slice,源slice) copy()的返回值是实际复制的元素个数,是较小的slice的长度 var a=[]int{1,2,3,5,8,7,10} var b=[]int{1,2,3,4,6,10} d:=copy(b,a) fmt.Println(d) //6 fmt.Println(b) //[1 2 3 5 8 7] 所以不存在复制导致的索引越界 */ copy(z,x) } z[len(x)]=y return z }
就地更改slice
package main import "fmt" func main() { data:=[]string{"one","","three"} fmt.Printf("%q\n",nonemty(data)) //["one" "three"] fmt.Printf("%q\n",data) //["one" "three" "three"] s:=[]int{5,6,7,8,9} fmt.Println(remove(s,2)) // [5 6 8 9] } //输入和输出有相同的底层数组,避免在函数内部重新分配一个数组,底层数组的元素被部分修改 func nonemty(strings []string) []string { i:=0 for _,s:=range strings{ if s!=""{ strings[i]=s i++ } } return strings[:i] } //移除slice中的某个元素,保持原来的顺序不变 func remove(slice []int,i int) []int { //copy 把第二个切片的元素赋值copy到第一个切片总 copy(slice[i:],slice[i+1:]) return slice[:len(slice)-1] }