Go语言4-数组、切片及map

1、数组
数组长度定义后不可修改,通过内置函数len()来获取数组元素个数

1)类型
    //长度为32的byte数组,每个元素为一个字节
    [32]byte

    //长度为2*N的复杂类型数组
    [2*N] struct{x,y int32}

    //长度100的指针数组
    [100]*float64

    //二维数组,等同于[2]([3]int)
    [2][3]int

    //三维数组
    [2][2][2]float64
2)定义
    //定义一个长度为5的数组,默认会使用int类型的零值(0)进行初始化
    arr := [5]int{}

    //与上面一句作用一样
    var arr [5]int = [5]int{}

    //定义一个长度为5的数组,其中arr[0]将被初始化为1,其余依旧是0
    arr := [5]int{1}

    //定义一个长度为5的数组,其中arr[0]、arr[4]将被初始化为1,其余依旧是0
    arr := [5]int{0:1,4:1}

    //定义一个长度为5的数组,默认会使用int类型的零值(0)进行初始化
    arr := new([5]int)

    //定义并初始化一个数组,这里会自动推断数组长度([...]起的作用),这里需要跟后面切片定义的不同(没有...)
    arr := [...]int{1, 2, 3, 4, 5}

    //定义并初始化一个数组,并且会自动推断长度为5,arr[4]将被初始化为1,其余依旧是0
    arr := [...]int{4:5}
3)遍历
    //与其它编程语言类型的遍历方式
    //获取数组arr的长度
    lenth := len(arr)             
    for i := 0; i < lenth; i++ {  
         //使用数组索引方式遍历数组
         fmt.Print(arr[i], " ")
    }
    //使用range方式遍历数组,range有两个返回值,1为索引,2为值
    for i, v := range arr {
         fmt.Print("[",i,"]=",v, " ")
    }
4)比较操作
在两个数据是同一类型(长度及元素类型)时,可以使用==与!=对两个数组进行比较,但不能使用<或>。
注:Go语言中数组是一个值类型,所有值类型变量在赋值和作为参数传递时都将产生一次复制动作,
    传入函数中的数组仅是该数组的一个副本,因此就无法对其进行修改,如果此时的数组较大时,
    将会降低程序的效率,关于这种场景的解决,下面的切片会进行讲解。

2、切片

在上面我们提到数组两个特点:
1、数据长度在定义后无法再次进行修改;
2、数据是值类型,每次传递都将产生一个副本;
而Slice(切片)正是为解决以上两个问题而存在。
从表象看,切片是一个指向原始数组的指针,但实际上,切片拥有自己的数据结构
1、一个指向原生数组的指针
2、数组切片中的元素个数
3、数组切片已分配的存储空间
这里需要区分两个概念,
长度:切片已使用的大小,从切片头开始算起,使用内置函数len()获取
容量:切片允许使用的大小,从切片头开始算起,至底层数组末尾,使用内置函数cap()获取,
      当切片长度超过容量时,会重新分配一个原容量两倍的容间,并将值复制过去,与Java
      中的ArrayList有点类似,要注意扩容后的内存地址与原内存地址不一样。

1)定义
    //此处先定义一个数组
    arr      := [5]int{}
    //基于上面定义的数据定义一个指向arr索引值在[0,5)范围(左开右闭)的切片
    //这里的[m,n]还可以有多种写法,如[:5]表示[0,5),[1:]表示[1,len(arr)),[:]表示[0,len(arr))
    arrSlice := arr[0:5]

    //定义一个长度为5,容量也为5的切片,这里要注意跟上面数组定义的差别,数组定义时中括号中有...
    arrSlice := []int{1,2,3,4,5}

    //定义一个长度为5,容量也为5的切片
    mySlice  := make([]int,5)

    //定义一个长度为5,容量为10的切片
    mySlice  := make([]int,5,10)

    //在切片上再切片,这种情况又叫做reslice,这里的[m:n]必须满足0<=m
    mySlice2 := mySlice[:]
在reslice的情况下,有很多地方需要注意,因为原slice与reslice实际底层使用的是同一块内存
空间,当两个的长度都在底层数组的长度内时,两者共享的都是同一块容间,当有一个超过之后,
这种情况将会被打破。如下面的代码所示:
    mySlice    := make([]int,5,6)
    //即mySlice[1]对应mySlice2[1],以此类推
    mySlice2   := mySlice[1:]
    //这里相当于同时也对mySlice2[0]的值进行了修改
    mySlice[1]  = 10
    //append为内置函数,表示给切片追加值,mySlice长度增加了,但mySlice2长度依旧不变
    mySlice     = append(mySlice,1)
    //这里将会把mySlice[5]的值覆盖为2,即覆盖上一句代码的值
    mySlice2    = append(mySlice2,2)
    //经过上面代码,已经用完所有空间,再添加值时,将会发生空间分配
    mySlice2 = append(mySlice2, 7)
    //这里仅改变了mySlice2[0],而mySlice[1]不变
    mySlice2[0] = -1
2)遍历与数组遍历一样,这里就不复述了

3)切片的增减
    //在切片末尾添加值 1 ,如果超过容量,会导致重新分配容间,容量会是原容量的2倍
    mySlice = append(mySlice,1)

    //在切片末尾同是添加多个值
    mySlice = append(mySlice,1,2,3)

    //在切片末尾追加一个数组,这里的"..."是必需的,否则会编译错误,表示把数组打散后传入
    mySlice = append(mySlice,arr...)

    //在切片末尾添加另一个切片,这里mySlice2后的[:]被省略了
    mySlice = append(mySlice,mySlice2...)

    //切片的减,这里表示删除掉了mySlice[1],切片的长度减小,但容量不变
    mySlice = append(mySlice[:1],mySlice[2:]...)

    //切片的减,如果是要删除切片末尾的话,则可以使用reslice的方式为实现
    mySlice = mySlice[0 : len(mySlice)-1]
4)内容复制
用于将内容从一个数组切片复制到另一个数组切片。
如果两个切片不一样大,将以较小切片的元素个数进行复制
    //这里要注意顺序,与Java的那种前者from后者to相反
    copy(targetSlice,sourceSlice)

3、map
未排序的键值对集合,系统直接内置,无需引入其它包

1)声明
var 变量名 map[键类型]值类型
    var myMap map[int]string
2)创建
    //创建一个key为int,值为string的map,myMap需要先声明
    myMap = make(map[int]string)

    //声明+创建
    myMap := make(map[int]string)

    //创建一个容量为100的map
    myMap = make(map[int]string,100)

    //声明+创建
    myMap = map[int]string{}

    //声明+创建+初始化
    myMap = map[int]string{1: "1"}
3)元素赋值、删除、查找
    //增加或修改key=123对应的元素值为字符型"123"
    myMap[123] = "123"

    //删除key=123对应的元素
    delete(myMap,123)

    //查找key=123对应的元素,该操作有两个返回值,多返回值知识点将在函数相关内容说到,
    //返回值1为对应的值,返回值2为是否包含该key
    v, ok := myMap[123]

本文介绍了编程中最常用的两种数据结构,数组及map,同时介绍了一种可伸缩的”数组”又可以看作为一个数组指针–切片,数组与切片有太多相似的地方,但同时又存在差异,所以做为新手要特别注意。

无闻(unknow)《Go编程基础》
许式伟的 《Go语言编程》

你可能感兴趣的:(go语言编程)