Go语言基础—切片

Go语言基础—切片由于长度是可变,可以解决数组长度在数据个数不确定情况下浪费内存的问题。切片和数组声明时语法最主要区别就是长度。

大家好,欢迎来到IT知识分享网。

Go语言基础—切片

切片(slice)

  • 切片:具有可变长度相同类型元素序列
  • 由于长度是可变,可以解决数组长度在数据个数不确定情况下浪费内存的问题
  • 切片和数组声明时语法最主要区别就是长度
//slice源码 type slice struct { array unsafe.Pointer //指向存放数据的数组指针 len int //长度有多大 cap int //容量有多大 }
func main() { var slice []string //切片 var array [3]string //数组 }
  • 切片只声明时为nil,没有开辟内存空间,不能直接操作切片,现需要先初始化

注意:切片只能和nil进行判断是否相等

func main() { var slice []string //切片 fmt.Println(slice == nil) //输出:true fmt.Printf("%p", slice) //输出:0x0 }

定义切片

  • 方式一:直接定义

通过直接指定初始值初始化一个切片变量

func main() { names := []string{"smallming", "little ming"} fmt.Println(names) //输出:[smallming little ming] }
  • 方式二:通过数组产生切片

定义数组后,取出数组中一个片段,这个片段就是切片类型

func main() { names := [3]string{"z3", "l4", "w5"} s := names[0:2] //包前不保后 fmt.Printf("%T", s) //输出:[]string fmt.Println(s) //输出:[z3 l4] }
  • 方式三:通过make函数产生切片

make(类型,初始长度[,初始容量])

长度表示切片中元素的实际个数,容量表示切片占用空间大小,且切片成倍增加,当增加到1024后按照一定百分比增加

len(slice)查看切片的长度

cap(slice)查看切片的容量

func main() { slice := make([]string, 0) //长度为0的切片,没有第三个参数表示容量和长度和长度相等 slice1 := make([]string, 0, 2) //长度为0,容量为2 fmt.Println(len(slice), cap(slice)) //0 0 fmt.Println(len(slice1), cap(slice1))//0 2 }

切片是引用类型

引用类型在变量之间赋值时传递的是地址,引用类型变量就是这个类型的指针,切片就是引用类型

func main() { names := []string{"smallming", "littleming"} names1 := names names1[0] = "张" fmt.Println(names, names1) //输出:[张 littleming] [张 littleming] fmt.Printf("%p %p", names, names1)//地址相同0xc000098420 0xc000098420 }
Go语言基础—切片

切片的相关操作

(1)产生切片

切片的产生,可以详见上面部分《定义切片》内容。以下为一些需要了解的注意事项:

1、如果增加后切片的长度没有超出数组,修改切片也是在修改数组;

2、如果增加后切片的长度超出数组,会重新开辟一块内存空间存放切片的内容;

3、通过下面代码也正面了切片内容中内容存在一块连续空间(和数组一样);

代码示例:

func main() { names := [3]string{"z3", "l4", "w5"} s := names[0:2] //包前不保后 fmt.Printf("%p, %p\n", s, &names[0]) //输出内存地址一致:0xc000070330, 0xc000070330 s[0] = "Go语言" s = append(s, "区块链") fmt.Println(s) //输出:[Go语言 l4 区块链] fmt.Println(names) //输出:[Go语言 l4 区块链] fmt.Printf("%p, %p\n", s, &names[0]) //内存地址相同 s = append(s, "超出了数组长度") fmt.Println(s) fmt.Println(names) fmt.Printf("%p, %p\n", s, &names[0]) //切片内存地址改变:0xc000048060, 0xc000070330 }

大家想进一步了解切片的内存变化,可以看看下面的这篇文章:

Go语言基础进阶—切片容量的变化

(2)删除实现

  • Go语言标准库中没有提供删除的函数
  • 切片也可以取其中的一段形成子切片,利用这个特性可以实现删除效果
func main() { num := []int {0,1,2,3,4,5,6} //要删除脚标n的元素 n:=2 num1:=num[0:n] num1=append(num1,num[n+1:]...) fmt.Println(num1) }

(3)append函数,添加实现

  • append()在Go语言标准库中源码如下
func append(slice []Type, elems ...Type) []Type
  • 可以向切片中添加一个或多个值,添加后必须使用切片接收append()函数返回值
func main() { s1 := make([]string, 0) fmt.Println(len(s1), cap(s1))//0 0 s2 := append(s1, "z3", "test3") fmt.Println(len(s2), cap(s2))//2 2 s3 := append(s2, "smallming") fmt.Println(len(s3), cap(s3)) //3 4 }
  • 如果添加一次添加多个值,且添加后的长度大于扩容一次的大小,容量和长度相等,等到下次添加内容时,如果不超出扩容大小,在现有的基础上进行翻倍
func main() { s1 := make([]string, 0) fmt.Println(len(s1), cap(s1)) //0 0 s2 := append(s1, "z3", "test3") fmt.Println(len(s2), cap(s2)) //2 2 s3 := append(s2, "smallming") fmt.Println(len(s3), cap(s3)) //3 4 s4 := append(s3, "4", "5", "6", "7", "8", "9") fmt.Println(len(s4), cap(s4)) //9 9 fmt.Println(s4) //[z3 test3 smallming 4 5 6 7 8 9] 长度为9,容量为9 s5 := append(s4, "10") fmt.Println(len(s5), cap(s5)) //10 18 容量在上次9的基础上翻倍 fmt.Println(s5) //[z3 test3 smallming 4 5 6 7 8 9 10] }

也可以把一个切片的内容之间添加到另一个切片中,需要注意语法中三个点

func main() { s := make([]string, 0) s1 := []string{"smallming", "test"} s = append(s, s1...) //注意此处,必须有三个点 fmt.Println(s) //[smallming test] }

(4)copy函数,操作切片

  • 通过copy函数可以把一个切片内容复制到另一个切片中
  • Go语言标准库源码定义如下

第一个参数是目标切片,接收第二个参数内容

第二个参数是源切片,把内容拷贝到第一个参数中

func copy(dst, src []Type) int
  • 拷贝时严格按照脚标拷贝
  • 把短切片拷贝到长切片中
func main() { num1 := []int{0, 1, 2, 3} num2 := []int{4, 5, 6, 7, 8} copy(num2, num1) fmt.Println(num1, num2) //[0 1 2 3] [0 1 2 3 8] }
  • 把长切片拷贝到短切片中
func main() { num1 := []int{0, 1, 2, 3} num2 := []int{4, 5, 6, 7, 8} copy(num1, num2) fmt.Println(num1, num2) //[4 5 6 7] [4 5 6 7 8] }
  • 把切片片段拷贝到切片中
func main() { num1 := []int{0, 1, 2, 3} num2 := []int{4, 5, 6, 7, 8} copy(num2, num1[2:]) fmt.Println(num1, num2) //[0 1 2 3] [2 3 6 7 8] }
  • 使用copy完成删除元素
func main() { s := []int {1,2,3,4,5,6,7,8} n := 2 //要删除元素的索引 newslice := make([]int, n) copy(newslice, s[0:n]) newslice = append(newslice, s[n+1:]...) fmt.Println(s) //原切片不变 fmt.Println(newslice) //删除指定元素后的切片 }

(5)sort包操作切片

  • Go语言标准库中sort提供了排序API
  • sort包提供了多种排序算法,这些算法是内部实现的,每次使用sort包排序时,会自动选择最优算法实现

1、插入排序

2、快速排序

3、堆排

  • sort包中最上层是一个interface的接口,只要满足sort,interface类型都可以排序
type Interface interface { // Len is the number of elements in the collection. Len() int // Less reports whether the element with // index i should sort before the element with index j. Less(i, j int) bool // Swap swaps the elements with indexes i and j. Swap(i, j int) }
  • Go语言标准库默认提供了对int,float64,string进行排序API
  • 很多函数的参数都是sort包下类型,需要进行转换

排序实现

  • 对int类型切片排序
func main() { s := []int{1, 7, 6, 9, 8} sort.Ints(s) //升序 fmt.Println(s) //[1 6 7 8 9] sort.Sort(sort.Reverse(sort.IntSlice(s))) //降序 fmt.Println(s) //[9 8 7 6 1] }
  • 对float64类型切片排序
func main() { f := []float64{1.5, 7.2, 5.8, 2.3, 6.8} sort.Float64s(f) //升序 fmt.Println(f) //[1.5 2.3 5.8 6.8 7.2] sort.Sort(sort.Reverse(sort.Float64Slice(f))) //降序 fmt.Println(f) //[7.2 6.8 5.8 2.3 1.5] }
  • 对string类型切片排序

1、按照编码表数值进行排序

2、多字符串中按照第一个字符进行比较

3、如果第一个字符相同,比较第二个字符

func main() { s := []string{"我", "我是中国人", "a", "d", "国家", "你", "我a"} sort.Sort(sort.StringSlice(s)) fmt.Println(s) //升序:[a d 你 国家 我 我a 我是中国人] //查找内容的索引,如果不存在,返回内容应该在升序排序切片的哪个位置插入 fmt.Println(sort.SearchStrings(s, "你是")) //输出:3 sort.Sort(sort.Reverse(sort.StringSlice(s))) fmt.Println(s) //[我是中国人 我a 我 国家 你 d a] }

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/77316.html

(0)
上一篇 2024-08-06 16:33
下一篇 2024-08-06 17:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信