1数组
1.定义数组的格式:var argName = [n] type,n>=0 如 var data = [5] int;
2.数组长度也是类型的一部分,因此具有不同长度的数据为不同类型;
3.注意区分指向数组的指针和指针数组;
4.数组在go中为值类型;
5.数组之间可以使用==或!=进行比较,但不能使用大小与比较;
6.可以使用new来创建数组,此方法返回一个指向数组的指针;
7.go支持多维数组
8.定义二维数组: var arr [2][3]int,var arr [2][3]int {{1,2,3},{,6,7,8}}
因为不同长度的数组为不同类型,所以不同长度的数组之间不能直接用=赋值。可以用循环赋值,定义数组的时候就给数组赋值:a:= [2] int{1,1}则a为[1,1],若为a:= [2] int{1}则a为[1,0]
定义多维数组时:最外层可以省略为几维数组,而最内层不能省略,如a := [...][3] int{{1:1},{2:2}};
用var声明数组变量时数据类型后面可以不接{},而用冒号形式声明的必须接{}
定义数组时,可以省略[]内的...或者数字,系统会自动根据{}数据的个数进行推导
import (
"fmt"
)
func main (){
a := [2] int{1,2}
// 输出[1,1]
fmt.Println(a)
a := [2] int{1}
// 输出[1,0]
fmt.Println(a)
a := [20] int{19:2}
// 输出前19个元素为0,第20个(下标为19)为2
fmt.Println(a)
a := [...] int{1,2,3,4,5}
// 输出[1,2,3,4,5]
fmt.Println(a)
// 指向数组的指针
a := [...] int{99:5}
// 将a的地址赋值给p指针
var p *[100]int = &a
// 输出前99个为0,第一百个为5的数组,数组前有&;&[0,0...,5]
fmt.Println(p)
// 指针数组
x, y := 1,2
// 将x,y的地址赋值给a,a为int型指针数组,实际上保存的是指针
a := [...] *int{&x, &y}
fmt.Println(a)
// 用new创建指向数组的指针
p := new([10] int)
// 输出10个为0的数组,数组前有&;&[0,0...,5],表示为指向数组的指针
fmt.Println(p)
// 对下标为1的位置赋值为2
p[1] = 2
// 多维数组
a := [2][3] int{{1,1,2},{2,2,1}}
// 输出[[1,1,2,][2,2,1]]
fmt.Println(a)
a := [2][3] int{{1:1},{2:2}}
// 输出[[0,1,0,][0,0,2]]
fmt.Println(a)
// 最外层可以省略为几维数组,而最内层不能省略
a := [...][3] int{{1:1},{2:2}}
// 输出[[0,1,0,][0,0,2]]
fmt.Println(a)
}
func main(){
// 从第一位开始将最大的向最后一位冒
var b = [6] int {5,8,6,1,7,3}
length := len(b)
for i:=0;i<length;i++{
for j:=1;j<length-i;j++{
if b[j]<b[j-1]{
tem:=b[j]
b[j] = b[j-1]
b[j-1] = tem
}
}
}
fmt.Println(b)
//从第i加一个开始将最小的向前面冒
b = [6] int {5,8,6,1,7,3}
for i:=0;i<length;i++{
for j:=i+1;j<length;j++{
if b[j]<b[i]{
tem:=b[j]
b[j] = b[i]
b[i] = tem
}
}
}
fmt.Println(b)
}
数组遍历
用 for key,value:=range nums遍历数组,改变value的值并不会改变nums中的值,value只是定义的一个变量,每次循环将对应key的值赋值给变量value
import (
"fmt"
)
func main(){
// 声明数组
nums := [10] int {1,2,3,4,5}
for i:=0;i<len(nums);i++{
fmt.Println("i", i, "value", nums[i])
}
for key,value:=range nums{
fmt.Println("key", key, "value", value)
}
}
2.1切片
1.切片本身并不是数组,它指向底层的数组;
2.作为变长数组的替代方案,可以关联底层数组的局部或全部;
3.为引用类型;
4.可以直接创建或从底层数组获取生成;
5.使用len()获取元素个数,cap()获取容量;
6.一般使用make()创建
7.如果多个slice指向相同底层数组,其中一个的值改变会影响全部;
s:=[]int{10,20,30,40,50}
# s[0:3:5]表示截取s数组下标0-2的数据,截取的容量为5
slice := s[0:3:5]
切片创建形式:make([]type,len,cap),其中cap可以省略,则和len的值相同,len表示存数的元素个数,cap表示容量,type为类型,int等。
容量表示本切片最多可以容纳多少个元素,如果超过这个容量,则系统会自动重新分配一个2倍容量的地址供使用,如果不够就以1倍,2倍,4倍,8倍这样的扩展下去,因为重新分配地址很耗性能,故通常先定义好。
切片创建var s1 [] int,[]中为空就表示为切片,为...或数字表示为数组
切片的下标都py一样是前闭后开,也可以用[5:],[:5]进行切片
go中数组是定长的,切片可以看成一种变长数组。
import (
"fmt"
)
func main(){
// 声明数组
var a [2] int
a = [2] int {1,2}
// 声明切片
var s1 [] int
fmt.Println(s1)
fmt.Println(a)
b := [10] int{}
// 切片
s2 := b[5:10]
fmt.Println(b)
// 取单独某个元素
fmt.Println(b[0])
fmt.Println(s2)
s3 := make([] int, 3, 10)
fmt.Println(s3, len(s3), cap(s3))
}
使用切片需要注意,切片为引用类型,当新添加的元素后的长度大于切片容量,则会重新分配一个切片,容量为之前容量的两倍,此时的切片和之前的切片不是同一个对象。
示例如下,当s容量大于等于1时,则元素成功添加到切片(因为为引用类型,且不会进行重新分配切片),而此处容量为0,故元素没有添加到s切片(因为重新分配切片,ping里面的s跟pong里面的s已经不是同一个对象了)
func Ping(s []int){
s = append(s, 3)
}
func Pong(){
s := make([]int, 0)
fmt.Println(s)
Ping(s)
fmt.Println(s)
}
2.1.1reslice
1.Reslice时索引以被切片的切片为准;
2.索引不可以超过被切片的切片的容量cap()值;
3.索引越界不会导致底层数组的重新分配而是引发错误
切片后,切片的容量为所切切片的起始位置到数组的末尾的元素个数,故可以在该切片上进行再次切片,再次切片时索引以被切切片的索引为准,最大下标为该切片的容量,示例如下
import (
"fmt"
)
func main(){
c := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
// 切片,sa为[c,d,e]sb为[d,e],sc为[f,g],sa的容量为9(从切片起始位置到原数组末尾)
sa := c[2:5]
sb:=sa[1:3]
sc:=sa[3:5]
fmt.Println(sa)
}
2.2切片方法
2.2.1append方法
1可以在slice尾部追加元素;
2.可以将一个slice追加在另一个slice尾部;
3.如果最终长度未超过追加到slice的容量则返回原始slice;
4.如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据。
数组不能使用append方法,切片可以;用法 s5 = append(s5, 1, 2, 3)
在s5切片中追加1,2,3并返回给s5
当从一个数组中切两个切片,切片元素有重叠部分时,修改一个切片的重叠元素,则另一个也会改变值(因为切片为引用类型,原理跟py的一样),当给一个切片中添加了元素超过它的容量后在修改重叠值,则另一个不会改变(因为当超过了容量时,系统将给切片返回一个新的地址,所以修改不会影响另一个切片)
import (
"fmt"
)
func main(){
c := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
// 切片
sa := c[2:5]
sb:=sa[1:3]
fmt.Println(sa)
s5 := make([] int, 3, 6)
fmt.Println(s5)
s5 = append(s5, 1, 2, 3)
fmt.Println(s5)
}
2.2.2copy方法
用法:copy(to_copy,by_copy);将by_copy这个数组copy给to_copy这个数组
1.将短数组copy给长数组,则长数组的前n(短数组元素个数)个值将变为短数组的值,后面的继续为之前对应下标的值;s1=[1,2,3],s2=[9,8,7,6,5],copy(s2,s1);则s2变为[1,2,3,6,5]
2.将长数组copy给短数组,则将只保留长数组的前n(短数组的元素个数)个元素至短数组;s1=[1,2,3],s2=[9,8,7,6,5],copy(s1,s2);则s1变为[9,8,7]
3.copy(s1[2:3],s2[5:6]) ;将s2下标为5和6的两个元素copy至s1中下标为2和3的位置; s1=[1,2,3],s2=[9,8,7,6,5],copy(s1[1:2],s2[3:4])
import (
"fmt"
)
func main(){
s1 := []string{"a", "b", "c"}
// 切片
s2 := []string{"f", "g", "h", "i", "j", "k"}
copy(s1,s2)
fmt.Println(s5)
}
2.2.3切片实现删除方法
seq := []string{"a", "b", "c", "d", "e"}
# 删除下标为2的数据
index := 2
# 通过再次切片和append实现删除
seq = append(seq[:index], seq[index+1:]...)
3数组和切片区别
slice和数组在声明时的区别:声明数组时,方括号内写明了数组的长度或使用...自动计算长度;如a := [...]int{1,2,3} a := [3]int{1,2,3},而声明slice时,方括号内没有任何字符;如a:= []int{1,2,3} a := make([]int, 5) a := make([]int, 5, 10);。
可以看见切片初始化时[]是空的,表明是切片类型,而数组中是必须有值的
当作为参数传递给函数时,数组传递的是值,而切片是地址,因为会将数组整个拷贝一份得到值传递,所以效率不如切片高;
func changeArray(a [3]int) {
}
func changeSlice(s []int) {
}
网友评论