6.go语言数组和切片

数组

在内存中连续存储的多个同一类型元素的集合,Go 语言中不允许混合不同类型的元素,数组中的所有元素都被自动赋值为数组类型的零值,数组中的每个变量都可以使用数组下标访问,len()函数返回数组元素个数

数组的声明及添加元素

数组一般声明语法如下:

var 数组变量名 [数组元素数量] 元素的数据类型

例如:

package main
import "fmt"
func main() {
    var a [3] int//声明一个长度为3的int数组
    fmt.Println(a)//输出[0 0 0]
}

简略声明也可以用来声明数组,不需要给数组中所有元素赋值,而且还可以忽略数组长度,使用…代替,这种形式声明的数组,初始化索引的顺序是无关紧要的,而且没用到的索引可以省略,未指定初始值的元素将用零值初始化

package main
import "fmt"
func main() {
    a := [3] int {1,2,3}//简略声明一个长度为3的int数组,并给每一个元素赋值
    fmt.Println(a)//输出[1 2 3]
    b := [3] int {1}//简略声明一个长度为3的int数组,给第一个元素赋值为1,剩下元素自动填充默认值0
    fmt.Println(b)//输出[1 0 0]
    c := [...] int {1,2,3,4,5}//简略声明一个不确定长度的数组,后面跟了5个元素的赋值,编译器会自动计算数组长度为5
    fmt.Println(c)//输出[1 2 3 4 5]
    d := [...] int {9:2}//简略声明一个数组,数组下标为9的元素为2,其余为int类型零值
    fmt.Println(d)//输出[0 0 0 0 0 0 0 0 0 2]
    e := [3] int {}//简略声明一个长度为3的数组,未赋值
    fmt.Println(e)//输出[0 0 0]
}

长度不同的数组在go语言中是不同类型的,长度不同的数组之间不能转换

package main
import "fmt"
func main() {
    a := [3] int {1}
    b := [...] int {1,2,3}
    a = b//a,b数组长度相同,可以当做是同一类型
    fmt.Println(a)//a数据的值改变,输出[1 2 3]
    c := [...] int {1}
    //b = c//b,c数组长度不同,会报错cannot use c (type [1]int) as type [3]int in assignment
    fmt.Println(c)//输出[1]
}

go中的数组是值类型不是引用类型,数组赋值给新变量,新变量得到的是原数组的副本,新变量中的数组改变不会影响原数组

package main
import "fmt"
func main() {
    a := [...] int {1,2,3}
    b := a
    b[0] = 9//改变了数组b的第一个元素
    fmt.Println(a)//原数组不会改变,输出[1 2 3]
    fmt.Println(b)//输出[9 2 3]
}
多维数组

go语言也可以创建多维数组,多维数组很容易管理具有父子关系的数据或者与坐标系相关联的数据

package main
import "fmt"
func main() {
    a := [3][2] int {//创建一个二维数组
    {1,2},
    {3,4},
    {5,6},//此处的,是必要的
    }
    fmt.Println(a[0][1])//输出2
}

只要类型一致,就可以将多维数组互相赋值

package main
import "fmt"
func main() {
    a := [2][2] int {{1,2},{1,2}}
    b := [2][2] int {{3,2},{3,2}}
    fmt.Printf("改变前a:%d\n",a)
    fmt.Printf("改变前b:%d\n",b)
    a = b
    fmt.Printf("改变后a:%d\n",a)
    fmt.Printf("改变后b:%d\n",b)
    /*
    输出:
    改变前a:[[1 2] [1 2]]
    改变前b:[[3 2] [3 2]]
    改变后a:[[3 2] [3 2]]
    改变后b:[[3 2] [3 2]]
    */
}

也可以将多维数组中的某个维度当做一个数组,或指定多维下标指定多维数组中某一值

package main
import "fmt"
func main() {
    a := [2][2] int {{1,2},{3,4}}//二维数组中每个维度都是一个一维数组
    var array [2]int = a[1]//取出二维数组a中下标为1的维度,即[3,4]
    var value int = a[1][0]//取出二维数组a中一维下标为1,二维下标为0的值,即3
    fmt.Println(array)
    fmt.Println(value)
    /*
    输出:
    [3 4]
    3
    */
}
数组冒泡排序
package main
import "fmt"
func main(){
    arrary :=[...]int{3,9,8,6,4,0,1}
    temp:=0
    fmt.Printf("排序前%d",arrary)
    for i:=0;i<len(arrary)-1;i++{
        //控制相邻元素比较,满足条件交换数据
        for j:=0;j<len(arrary)-i-1;j++{
            if(arrary[j]>arrary[j+1]){
                temp=arrary[j]
                arrary[j]=arrary[j+1]
                arrary[j+1]=temp
            }
        }
    }
    fmt.Printf("排序后%d",arrary)
}

切片

切片是由数组建立的一种方便、灵活且功能强大的包装,是对数组一个连续片段的引用。切片本身不拥有任何数据。它们只是对现有数组的引用,切片的长度是切片中的元素数。Go语言切片的内部结构包含地址、大小和容量,切片的容量是从创建切片索引开始的底层数组中元素数

切片的声明及操作

切片的声明语法如下:

var 切片对象名 [] 数据类型 = 目标切片对象 [开始位置:结束位置]

例如:

package main
import "fmt"
func main() {
    a := [5] int {1,2,3,4,5}
    var b [] int = a[1:4]//创建一个a数组下标从1到(4-1)的切片
    fmt.Printf("a:%d \n",a)//输出a:[1 2 3 4 5]
    fmt.Printf("b:%d \n",b)//b:[2 3 4]
    //简略写法声明数组
    aa := [] int {1,2,3}//创建一个长度为3的数组,并返回其的切片引用,所以a是切片
    fmt.Printf("aa:%d \n",aa)//输出a:[1 2 3]
}

切片默认指向一段连续内存区域,可以是数组,也可以是切片本身,声明切片的格式中,开始和结束范围都被忽略,生成的切片将表示和原切片或数组一致的切片,并且生成的切片与原切片或数组在数据内容上是一致的;把切片的开始和结束位置都设为 0 时,生成的切片将变空

package main
import "fmt"
func main() {
    a := [5] int {1,2,3,4,5}
    var b [] int = a[0:3]//数组生成切片
    var c [] int = b[0:2]//切片生成切片
    fmt.Println(a,b,c)//输出[1 2 3 4 5] [1 2 3] [1 2]
    var bb [] int = a[:]//数组生成切片
    var cc [] int = bb[:]//切片生成切片
    fmt.Println(a,bb,cc)//输出[1 2 3 4 5] [1 2 3 4 5] [1 2 3 4 5]
    fmt.Println(cc[0:0])//空切片,输出[]
}

切片自己不拥有任何数据,只是底层数组的一种表示,对切片所做的任何修改都会反映在底层数组中

package main
import "fmt"
func main() {
    a := [5] int {1,2,3,4,5}
    b := a[2:3]//数组a从下标2到下标3-1的切片,即元素3
    fmt.Printf("修改切片前:%d\n",a)
    b[0] = b[0] + 1
    fmt.Printf("修改切片后:%d\n",a)
    /*
    输出:
    修改切片前:[1 2 3 4 5]
    修改切片后:[1 2 4 4 5]
    */
}
动态生成切片

使用make()函数可以动态生成切片,使用 make() 函数生成的切片一定发生了内存分配操作,语法格式如下:

make([]数据类型,切片元素数量,预分配的元素数量)

例如:

package main
import "fmt"
func main() {
    a := make([]int,2,3)//使用make()函数生成切片
    fmt.Println(a,len(a),cap(a))//输出[0 0] 2 3
}
为切片添加元素

使用append()函数可以为切片添加元素,使用append()函数添加切片元素,如果切片容量不够会重新分配内存

package main
import "fmt"
func main() {
    var a [] int
    for i:= 1;i <= 10;i++{
        a = append(a,i)//向切片a中添加元素
        fmt.Printf("len:%d,cap:%d,%d\n",len(a),cap(a),a)
    }
}

上面的方法是向切片尾部添加元素,下面是向切片头部添加元素,每一次都会导致重新分配内存,向切片的头部添加元素的性能要比从尾部追加元素的性能差很多

package main
import "fmt"
func main() {
    a := [] int {1}
    fmt.Println(a)//输出[1]
    a = append([] int {3},a...)//向切片头部添加元素
    fmt.Println(a)//输出[3 1]
}
复制切片

使用copy()函数可以复制一个数组切片到另一个数组切片,若两个数组切片不一样大,会按较小的数组切片的元素个数进行复制;copy()函数有返回值,会返回复制元素的个数,即最小切片的长度

package main
import "fmt"
func main() {
    a := [] int {1,2,3}
    b := [] int {0}
    copy(a,b)//复制b到a,b中只有一个元素,a中只会更改第一个元素
    fmt.Println(a)//输出[0 2 3]
    fmt.Println(b)//输出[0]
    aa := [] int {1,2,3}
    bb := [] int {0}
    copy(bb,aa)//复制aa到bb,bb的长度只有1,所以bb只会复制aa中的第一个元素
    fmt.Println(aa)//输出[1 2 3]
    fmt.Println(bb)//输出[1]
}
切片截取

切片截取就是,从切片中截取一部分数据形成新的切片,改变新切片中的内容,原始切片也会改变

func main(){
	//定义切片并初始化
	s:=[]int{1,2,3,45,55,66,234,443}
	//从切片中截取数据,改变新切片中值的内容,会影响原始切片
	slice:=s[0:5:5]//s[low:high:max]
	fmt.Println(slice)
	slice[1]=9787
	fmt.Println(slice)
	fmt.Println(s)
}

切片截取其他操作

语法说明
s[n]切片s中索引位置为n的项
s[:]从切片s的索引位置0到len(s)-1处所获得的切片,即切片的所有数据
s[n:]从切片s的索引位置n到len(s)-1处所获得的切片
s[:n]从切片s的索引位置0到n处所获得的切片,n不能大于切片长度
s[m:n]从切片s的索引位置m到n处所获得的切片,m和n最大范围等于切片长度,即len(s)=m-n
s[m:n:cap]从切片s的索引位置m到n处所获得的切片,指定了新切片的容量,cap的值最小要等于n

切片的容量可以自动增长,小于1024时,每次成2倍增长,len()函数可以获取切片长度,cap()函数可以获取切片容量

func main(){
	//切片长度小于1024
	ar:=make([]int,3,4)
	fmt.Println(len(ar),cap(ar))//cap()值为4
	//追加3个元素
	ar=append(ar,2,2,1)//cap()值为8
	fmt.Println(len(ar),cap(ar))
	arr:=make([]int,1024,1024)
	fmt.Println(len(arr),cap(arr))
	arr=append(arr,1,2)
	fmt.Println(len(arr),cap(arr))
}
多维切片

切片也可以像数组一样,有多维切片的存在

package main
import "fmt"
func main() {
    //创建一个多维切片
    a := [][] int {{1,2},{3}}
    fmt.Println(a)//输出[[1 2] [3]]
    //给第一个切片追加一个元素
    a[0] = append(a[0],8)
    fmt.Println(a)//输出[[1 2 8] [3]]
}

遍历数据和切片

可以使用range语句遍历数组和切片,for循环也可以用于遍历,但是range语句可以返回索引和该索引处的值

package main
import "fmt"
func main() {
	//遍历数组
    a := [...] int {1,2,3,4,5}
    //如果希望去除索引,可以使用_替换i
    for i,v := range a {
        fmt.Printf("数组下标:%d,值:%d\n",i,v)
    }
    /*
    输出:
    数组下标:0,值:1
    数组下标:1,值:2
    数组下标:2,值:3
    数组下标:3,值:4
    数组下标:4,值:5
    */
    //遍历切片
    b:=[]string{"a","b","c","d","e"}
    for num,value:=range b {
    	fmt.Printf("下标%d,值%s\n",num,value)
    }
    /*
    输出:
    下标0,值a
	下标1,值b
	下标2,值c
	下标3,值d
	下标4,值e
    */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值