goto
-
• goto是Go语言中的一个关键字
-
• goto让编译器执行时跳转到特定位置
-
• Loop是标记名(Label),名称任意,习惯上名称为Loop
fmt.Println("执行程序")
i := 6
if i == 6 {
goto Loop
}
fmt.Println("if下面输出")
Loop:
fmt.Println("loop")
-
• 可以有多个,但是标签(Labal)定义了就必须使用
fmt.Println("执行程序")
i := 6
if i == 6 {
goto Loop
}
fmt.Println("if下面输出")
Loop:
fmt.Println("loop")
Loop1: //报错:label Loop1 defined and not used
fmt.Println("Loop1")
-
• goto也可以用于跳出循环,执行指定标签位置代码
for i := 0; i < 5; i++ {
fmt.Println(i)
if i == 2 {
goto abc
}
}
fmt.Println("for循环执行结束")
abc:
fmt.Println("abc")
fmt.Println("程序结束")
切片
-
• 切片的英文名称slice
-
• 切片:具有可变长度相同类型元素序列.
-
• 由于长度是可变,可以解决数组长度在数据个数不确定情况下浪费内存的问题.
-
• 切片和数组声明时语法最主要的区别就是长度
var slice []string //切片
var array [3]string //数组
-
• 切片只声明时为nil,没有开辟内存空间,不能直接操作切片,需要先初始化
-
• 注意:切片只能和nil进行判断是否相等
var slice []string //切片
fmt.Println(slice==nil)//输出:true
fmt.Printf("%p",slice)//输出:0x0
定义切片
-
• 通过直接指定初始值定初始化一个切片变量
names := []string{"hello", "world"}
fmt.Println(names)
-
• 定义完切片后就可以通过
切片对象[脚标]
取出或修改切片中元素内容.语法和数组相同
切片是引用类型
-
• 引用类型在变量之间赋值时传递的是地址.引用类型变量就是这个类型的指针.切片就是引用类型
-
• 值类型在变量之间赋值时传递的是值的副本
names := []string{"hello", "world"}
names1 := names
names1[0] = "a"
fmt.Println(names, names1)//输出:[a world] [a world]
fmt.Printf("%p %p",names,names1)//地址相同
make函数
-
• Go语言中可以使用make函数创建slice 、 map、 channel、 interface
-
• 使用make函数定义无内容,但是不是nil的切片,意味着切片已经申请了内存空间
-
•
make(类型,初始长度[,初始容量])
-
• 初始容量可以省略,默认和长度相等
slice := make([]string, 0) //长度为0的切片,没有第三个参数表示容量和长度相等
slice1 := make([]string, 0, 2) //长度为0,容量为2
fmt.Println(slice, slice1)
-
• 长度表示切片中元素的实际个数,容量表示切片占用空间大小,且切片容量成倍增加.当增加到1024后按照一定百分比增加.
-
• len(slice) 查看切片的长度
-
• cap(slice) 查看切片的容量
slice := make([]string, 0) //长度为0的切片,没有第三个参数表示容量和长度相等
slice1 := make([]string, 0, 3) //长度为0,容量为2
fmt.Println(len(slice), cap(slice))
fmt.Println(len(slice1), cap(slice1))
append()函数
-
• append()在Go语言标准库中源码如下
// The append built-in function appends elements to the end of a slice. If
// it has sufficient capacity, the destination is resliced to accommodate the
// new elements. If it does not, a new underlying array will be allocated.
// Append returns the updated slice. It is therefore necessary to store the
// result of append, often in the variable holding the slice itself:
// slice = append(slice, elem1, elem2)
// slice = append(slice, anotherSlice...)
// As a special case, it is legal to append a string to a byte slice, like this:
// slice = append([]byte("hello "), "world"...)
func append(slice []Type, elems ...Type) []Type
-
• 可以向切片中添加一个或多个值,添加后必须使用切片接收append()函数返回值
s := make([]string, 0)
fmt.Println(len(s), cap(s))//输出:0 0
s = append(s, "msr", "MaiShuRen")
fmt.Println(len(s), cap(s))//输出:2 2
s = append(s, "MaiShuRen")
fmt.Println(len(s), cap(s))//输出:3 4
-
• 如果添加一次添加多个值,且添加后的长度大于扩容一次的大小,容量和长度相等.等到下次添加内容时如果不超出扩容大小,在现在的基础上进行翻倍
s := make([]string, 0)
fmt.Println(len(s), cap(s)) //输出:0 0
s = append(s, "msr", "MaiShuRen")
fmt.Println(len(s), cap(s)) //输出:2 2
s = append(s, "MaiShuRen")
fmt.Println(len(s), cap(s)) //输出:3 4
s = append(s, "4", "5", "6", "7", "8", "9")
fmt.Println(len(s), cap(s)) //输出:9 9
s = append(s,"10")
fmt.Println(len(s), cap(s)) //输出:10 18
-
• 也可以把一个切片的内容直接添加到另一个切片中.需要注意语法中有三个点
s := make([]string, 0)
s1 := []string{"msr", "MaiShuRen"}
s = append(s, s1...) //注意此处,必须有三个点
fmt.Println(s)
通过数组产生切片
-
• 定义数组后,取出数组中一个片段,这个片段就是切片类型
names := [3]string{"msr", "MaiShuRen", "Mai"}
s := names[0:2] //包前不包后
fmt.Printf("%T", s) //输出:[]string
fmt.Println(s) //输出:[msr MaiShuRen]
-
• 切片是指针,指向数组元素地址,修改切片的内容,数组的内容会跟随变化
names := [3]string{"msr", "MaiShuRen", "Mai"}
s := names[0:2] //包前不包后
fmt.Printf("%p %p",s,&names[0])//输出的地址是相同的
s[0] = "Go语言"
fmt.Println(s) //输出:[Go语言 MaiShuRen]
fmt.Println(names) //输出:[Go语言 MaiShuRen Mai]
-
• 当切片内容在增加时
-
• 如果增加后切片的长度没有超出数组,修改切片也是在修改数组
-
• 如果增加后切片的长度超出数组,会重新开辟一块空间放切片的内容
-
• 通过下面代码也正面了切片中内容存在一块连续空间(和数组一样)
names := [3]string{"msr", "MaiShuRen", "Mai"}
s := names[0:2] //包前不包后
fmt.Printf("%p %pn",s,&names[0])
s[0] = "Go语言"
s=append(s,"区块链")
fmt.Println(s) //输出:[Go语言 MaiShuRen 区块链]
fmt.Println(names) //输出:[Go语言 MaiShuRen 区块链]
fmt.Printf("%p %pn",s,&names[0])//地址相同
s=append(s,"超出了数组长度")
fmt.Println(s) //输出:[Go语言 MaiShuRen 区块链 超出了数组长度]
fmt.Println(names) //输出:[Go语言 MaiShuRen 区块链]
fmt.Printf("%p %pn",s,&names[0])//切片地址改变
删除实现
-
• Go语言标准库中没有提供删除的函数
-
• 切片也可以取其中的一段形成子切片,利用这个特性可以实现删除效果
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)
copy函数
-
• 通过copy函数可以把一个切片内容复制到另一个切片中
-
• Go语言标准库源码定义如下
-
• 第一个参数是目标切片,接收第二个参数内容
-
• 第二个参数是源切片,把内容拷贝到第一个参数中
// The copy built-in function copies elements from a source slice into a
// destination slice. (As a special case, it also will copy bytes from a
// string to a slice of bytes.) The source and destination may overlap. Copy
// returns the number of elements copied, which will be the minimum of
// len(src) and len(dst).
func copy(dst, src []Type) int
-
• 拷贝时严格按照脚标进行拷贝.且不会对目标切片进行扩容
代码示例
-
• 把短切片拷贝到长切片中
s1:=[]int {1,2}
s2:=[]int {3,4,5,6}
copy(s2,s1)
fmt.Println(s1)//输出:[1 2]
fmt.Println(s2)//输出:[1 2 5 6]
-
• 把长切片拷贝到短切片中
s1:=[]int {1,2}
s2:=[]int {3,4,5,6}
copy(s1,s2)
fmt.Println(s1)//输出:[3 4]
fmt.Println(s2)//输出:[3 4 5 6]
-
• 把切片片段拷贝到切片中
s1:=[]int {1,2}
s2:=[]int {3,4,5,6}
copy(s1,s2[1:])
fmt.Println(s1)//输出:[4 5]
fmt.Println(s2)//输出:[3 4 5 6]
使用copy完成删除元素
-
• 使用copy函数可以保证原切片内容不变
s := []int{1, 2, 3, 4, 5, 6, 7}
n := 2 //要删除元素的索引
newSlice := make([]int, n)
copy(newSlice, s[0:n])
newSlice = append(newSlice, s[n+1:]...)
fmt.Println(s) //原切片不变
fmt.Println(newSlice) //删除指定元素后的切片
切片的扩容策略
-
1. 如果申请的容量大于原来的两倍,那就直接扩容至新申请的容量。如:长度为3,容量为4的切片,现添加6个元素进入,那么长度就会变成9,大于原容量的两倍,所以切片的新容量会也会变成9
-
2. 如果小于1024,那么直接扩容两倍
-
3. 如果大于1024,就按照1.25被去扩容
-
4. 具体存储的值类型不同,扩容策略也有一定的不同
原文始发于微信公众号(杂食的程序员):golang学习七:goto、label和切片
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/247316.html