赞
踩
go语言中数组的长度是固定的,如果数组中元素个数已经等于数组容量时,就不能再继续往数组中添加新元素了。为了解决此问题,就有了切片(slice)类型,它是在数组的基础上重新进行了一层封装。
切片的本质就是对底层数组的封装,它包含了三个信息:底层数组的指针、切片的长度(len)和切片的容量(cap)。
语法:var 变量 [] 类型
表面上看,定义切片和定义数组是非常相似的,就是不用写明存储元素的个数即可。
```go
package main
import "fmt"
//切片的基本操作
func main() {
//基本定义
var a []int //声明一个整型切片
var b = []string{"liyifeng", "zhuyilong"} //声明一个string型切片并初始化
var c = []bool{true, false} //声明一个bool型切片并初始化
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
注意:切片是引用类型数据,必须要初始化才能使用,否则会报索引越界的错
通过切片表达式(a[start:end]),可以将一个数组类型转换为切片类型。注意:切片表达式的起止坐标不支持负数
package main
import "fmt"
//切片的基本操作
func main() {
//基本定义
var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
b := a[:] //拷贝整个数组 [1 2 3 4 5]
c := a[:3] //左闭右开的区间,结果[1 2 3]
d := a[3:] //左闭右开的区间,结果[4 5]
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
和上面的例子类似
package main
import "fmt"
//切片的基本操作
func main() {
//基本定义
var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
b := a[:] //拷贝整个数组 [1 2 3 4 5]
c := b[:3] //左闭右开的区间,结果[1 2 3]
d := c[3:] //左闭右开的区间,结果[]
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
make函数第2个参数表示长度,第3个参数表示容量,make容量不指定时,和长度保持一致。
func make(t Type, size …IntegerType) Type
基本初始化时提到过,切片没有初始化直接使用会提示索引越界的错误。一般会通过make函数对切片初始化为指定类型的空值。
package main
import "fmt"
//切片的基本操作
func main() {
//通过make函数初始化
//1.指定长度和容量
var a = make([]string, 2, 10)
fmt.Printf("%#v 长度:%d 容量:%d\n", a, len(a), cap(a))
//2.只指定长度,默认容量和长度一致
var b = make([]string, 2)
fmt.Printf("%#v 长度:%d 容量:%d\n", b, len(b), cap(b))
}
通过数组初始化切片时,切片的容量是从切片表达式start开始,到整个数组结束所有的数据大小。切片相当于对原始数组指定部分的一个别名而已,指向的还是相同的空间。
package main
import "fmt"
//切片的基本操作
func main() {
var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
b := a[:] //拷贝整个数组 [1 2 3 4 5]
c := a[:3] //左闭右开的区间,结果[1 2 3]
d := a[3:] //左闭右开的区间,结果[4 5]
fmt.Printf("%#v 长度:%d 容量:%d\n", a, len(a), cap(a))
fmt.Printf("%#v 长度:%d 容量:%d\n", b, len(b), cap(b))
fmt.Printf("%#v 长度:%d 容量:%d\n", c, len(c), cap(c))
fmt.Printf("%#v 长度:%d 容量:%d\n", d, len(d), cap(d))
}
package main
import "fmt"
//切片的基本操作
func main() {
var a = []int{1, 2, 3, 4, 5} //声明并初始化一个整型切片
for i := 0; i < len(a); i++ {
fmt.Println(a[i])
}
}
package main
import "fmt"
//切片的基本操作
func main() {
var a = []int{1, 2, 3, 4, 5} //声明并初始化一个整型切片
for idx, value := range a {
fmt.Printf("[idx]:%d [val]:%v\n", idx, value)
}
}
要检查切片是否为空,请始终使用len(s) == 0来判断,而不应该使用s == nil来判断。切片是引用类型,不支持直接比较,只能和nil比较。
通过内置的append函数实现切片元素的增加,如果超过切片的容量会自动扩容,其实也就是重新定义开辟了一块新的地址空间存放这些数据。所以append函数是有返回值的,需要用一个变量来接收。
package main
import "fmt"
//切片的基本操作
func main() {
var a = make([]int, 1) //声明一个整型切片
for i := 0; i < 10; i++ {
a = append(a, i)
fmt.Printf("%#v [len]:%d [cap]:%d\n", a, len(a), cap(a))
}
}
可以看到,append动态扩容的效果i,当长度在某个范围内,容量是按照当前容量的2倍进行扩容。
package main
import "fmt"
//切片的基本操作
func main() {
var a = make([]int, 1) //声明并初始化一个整型切片
a = append(a, 1, 2, 3, 4, 5)
fmt.Printf("%#v [len]:%d [cap]:%d\n", a, len(a), cap(a))
}
注意:因为切片定义的时候已经对第1个元素进行了零值初始化了,所以第1个元素是0。
package main
import "fmt"
//切片的基本操作
func main() {
var a = make([]int, 1) //声明并初始化一个整型切片
var b = []int{-10, -9, -8, -7} //声明并初始化一个整型切片
a = append(a, b...)
fmt.Printf("%#v [len]:%d [cap]:%d\n", a, len(a), cap(a))
}
和数组操作一致,按照下标即可修改切片内指定元素。注意:通过数组初始化的切片,修改了元素内容,本质上是对数组内容进行的修改【前提:没有动态扩容,否则切片指向的就是一个新地址了】
package main
import "fmt"
//切片的基本操作
func main() {
//基本定义
var a = [5]int{1, 2, 3, 4, 5} //声明一个整型数组
b := a[:] //拷贝整个数组 [1 2 3 4 5]
c := a[:3] //左闭右开的区间,结果[1 2 3]
d := a[3:] //左闭右开的区间,结果[4 5]
e := a[1:4]
c[2] = 1000
// e = append(e, 3000, 4000, 5000, 6000) //即使append操作,超过原有容量时,数组的值不会被修改
e = append(e, 3000) //即使append操作,不超过原有容量时,指向的还是原来数组的地址,所以数组的值也会被修改
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
fmt.Println(e)
}
如果执行的是屏蔽的append语句,可以看到完全不同的效果。
没有直接提供删除的函数,可以借助append函数实现。格式为:
a := append(a[:index], a[index+1:]…)
package main
import "fmt"
//切片的基本操作
func main() {
var a = []int{1, 2, 3, 4, 5, 6, 7, 8, 9} //声明并初始化一个整型切片
//删除4,5,6
b := append(a[:3], a[6:]...)
fmt.Printf("%#v [len]:%d [cap]:%d\n", b, len(b), cap(b))
}
由于切片是引用类型,指向了同一块内存地址。修改b的同时a的值也会发生变化。如果想完全复制一份的话就可以使用内置的copy函数,可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的定义如下:
copy(destSlice, srcSlice []T)
package main
import "fmt"
//切片的基本操作
func main() {
var a = []int{1, 2, 3, 4, 5, 6, 7, 8, 9} //声明并初始化一个整型切片
var c = make([]int, 3)
b := a[:2]
copy(c, b)
fmt.Println("//*******修改前:")
fmt.Printf("%#v\n", a)
fmt.Printf("%#v\n", b)
fmt.Printf("%#v\n", c)
fmt.Println("//*******修改后:")
b[1] = 1000
fmt.Printf("%#v\n", a)
fmt.Printf("%#v\n", b)
fmt.Printf("%#v\n", c)
}
参考链接:https://www.liwenzhou.com/posts/Go/06_slice/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。