08 Golang引用类型 |
您所在的位置:网站首页 › golang中的引用类型包括 › 08 Golang引用类型 |
08 Golang引用类型——切片
learninginto
· · 873 次点击 ·
·
开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
第一次,站长亲自招 Gopher 了>>>
切片
切片(slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容。 切片是一个引用类型,它的内部结构包括地址、长度和容量。 声明切片类型的基本语法如下: var name []T其中name表示变量名,T表示切片中的元素类型 var arr1 []int fmt.Printf("%v-%T-长度:%v", arr1, arr1, len(arr1))//[]-[]int-长度:4方式二:定义时初始化 var arr1 = []int{1, 3, 5, 7} fmt.Printf("%v-%T-长度:%v", arr1, arr1, len(arr1))//[]-[]int-长度:4方式三:赋值时带下标 var arr1 = []int{1:2, 2:4, 5:6} fmt.Printf("%v-%T-长度:%v", arr1, arr1, len(arr1)) //[0 2 4 0 0 6]-[]int-长度:6 nilgolang中,当声明了一个变量,却还并没有赋值值,golang中会自动赋值一个默认值。 类型 默认值 bool false numbers 0 string "" pointers nil slices(切片) nil maps/channels/functions nilgolang中声明切片的默认值是nil var arr1 []int fmt.Println(arr1 === nil) //true 切片的循环遍历 for var strSlice = []string{"php", "java", "nodejs", "golang"} for i := 0; i < len(strSlice); i++{ fmt.Println(strSlice[i]) } for range var strSlice = []string{"php", "java", "nodejs", "golang"} for k, v := range strSlice { fmt.Println(k, v) } } 基于数组定义切片获取数组中的所有值 a := [5]int{1, 3, 5, 7, 9} b := a[:] fmt.Printf("%v-%T", b, b) //[1 3 5 7]-[]int截取数组的某一部分[)——左包右不包 a := [5]int{1, 3, 5, 7, 9} b := a[1:4] c := a[3:]//获取第三个下标之后的数据 d := a[:3]//获取第三个下标之前的数据 fmt.Printf("%v-%T\n", b, b)//[3 5 7]-[]int fmt.Printf("%v-%T", c, c)//[5, 7]-[]int fmt.Printf("%v-%T", d, d)//[1 3 5]-[]int 切片再切片除了基于数组得到切片,还可以通过切片来得到切片 a := []string{"北京","上海","广州","深圳","成都","重庆"} b := a[1:] fmt.Printf("%v-%T\n", b, b)//[上海 广州 深圳 成都 重庆] 切片的长度及容量切片拥有自己的长度和容量,可以通过内置的len()函数求长度,cap()求容量。 切片的本质就是对底层数组的封装,它包含了三个信息:底层数据的指针、切片的长度(len)和切片的容量(cap) 长度是它所包含的元素个数 容量是从它的第一个元素开始,到其底层数组元素末尾的个数 s := []int{1, 2, 3, 4, 5, 6} fmt.Printf("长度%d 容量%d", len(s), cap(s)) //长度6 容量6 a := s[2:] fmt.Printf("长度%d 容量%d", len(a), cap(a)) //长度4 容量4 b := s[1:3] fmt.Printf("长度%d 容量%d", len(b), cap(b)) //长度2 容量5 c := s[:3] fmt.Printf("长度%d 容量%d", len(c), cap(c)) //长度3 容量6 make()函数来构造切片make([]T, size, cap)声明一个长度为size,容量为cap的切片 var sliceA = make([]int, 4, 8) fmt.Println(sliceA)//[0 0 0 0] fmt.Printf("%d-%d",len(sliceA), cap(sliceA))//4-8 切片的修改 var sliceA = make([]int, 4, 8) sliceA[0] = 10 sliceA[1] = 12 fmt.Println(sliceA)//[10 12 0 0] sliceB := []string{"js", "java", "go"} sliceB[2] = "node" fmt.Println(sliceB)//[js java node] 切片的扩容appendgolang中不能通过下标的方式给切片扩容,需要用到append()方法,类似于js中的concat() append()后面可以传多个参数 var sliceC []int fmt.Printf("值%v-长度%v-容量%v",sliceC,len(sliceC),cap(sliceC))//值[]-长度0-容量0 sliceC = append(sliceC, 12) fmt.Printf("值%v-长度%v-容量%v",sliceC,len(sliceC),cap(sliceC))//值[12]-长度1-容量1append合并切片 sliceA := []string{"php","java"} sliceB := []string{"node","go"} sliceA = append(sliceA, sliceB...) fmt.Println(sliceA)//[php java node go] 切片的扩容策略 首先判断,如果新申请容量大于2倍的旧容量,最终容量是新申请的容量 否则判断,如果旧切片的长度小于1024,则最终容量是旧容量的两倍;如果旧切片长度>=1024,则最终容量从旧容量开始循环增加原来的1/4,即(newcap = old.cap, for{newcap += newcap / 4}),直到最终容量大于新申请的容量 如果最终容量计算值溢出,则最终容量就是新申请容量需要注意的是,切片扩容还会根据切片中元素的类型不同而做不同的处理,比如int和string类型的处理方式就不一样。 var sliceA []int for i := 0; i < 5; i++{ sliceA = append(sliceA, i) fmt.Printf("%v长度%d 容量%d", sliceA, len(sliceA), cap(sliceA)) } //[1]长度1 容量1 //[1 2]长度2 容量2 //[1 2 3]长度3 容量4 //[1 2 3 4]长度4 容量4 //[1 2 3 4 5]长度5 容量8可以通过查看$GOROOT/src/runtime/slice.go源码,其中扩容相关代码如下: newcap := old.cap doublecap := newcap + newcap if cap > doublecap { newcap = cap }else { if old.len < 1024{ newcap = doublecap } else { for 0 < newcap && newcap < cap { newcap += newcap / 4 } if newcap |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |