10-Go语言数组和切片

Go语言数组数组

一维数组
  • 数组定义格式: var arr [3]int
  • 数组的初始化方式
    • 先定义后初始化
      注意点:Go语言数组支持先定义后一次性初始化
    //1.先定义后初始化
          var nums [3]int
          //先定义数组再逐个初始化
          nums[0] = 1
          nums[1] = 2
          nums[2] = 3
    
          //先定义数组再一次性初始化
          nums = [3]int{2,3,4}
          fmt.Println(nums)
    
    • 定义的同时初始化
      • 注意点:给数组一次性赋值的时候一定要在值的前面加上数组的类型,而且必须要和数据类型一模一样
      • C语言中数组没有初始化保存的是垃圾数据,Go语言中数组没有初始化保存的是零值
    //var arr [3]int = [3]int{2, 3, 4}
      //定义的同时部分初始化,未初始话的元素为0
      var arr [3]int = [3]int{1,3}
      //指定元素初始化
      var arr [3]int = [3]int{2:4}
      //[...]的含义, 让编译器根据赋值的元素个数自动计算数组的元素个数
      arr := [...]int{1,3,4}
      fmt.Println(arr)
      fmt.Println(arr[0])
      fmt.Println(arr[1])
      fmt.Println(arr[2])
    

零值
  • 什么是零值
    • 数据类型未初始化,系统自动添加的数据
    • 各种数据类型零值
      • int/int8/int16/int32/int64/uint/uint8/uint16/uint32/uint64/byte/rune/uintptr的默认值是0
      • float32/float64的默认值是0.0
      • bool的默认值是false
      • string的默认值是""
      • pointer/function/interface/slice/channel/map/error的默认值是nil

值类型
  • Go语言在数组中是值类型,所以数组之间的赋值是值拷贝关系,而不是指向关系
  • 如果想让两个数组可以相互赋值, 那么两个数组的类型必须一致类型一致包括元素个数, 元素个数也是Go语言中数组类型的一部分
  • 如果数组中存储的元素类型支持== != 操作,而且两个数组的类型是一个样的, 那么数组也支持== !=操作
package main

import "fmt"

func main() {
    nums := [...]int {2,3,4}
    arr := [...]int{2,3,4}
    fmt.Println(nums == arr) //true

    nums := [3]int{1,2,3}
    res := nums
    fmt.Println(res) //[1,2,3]

    nums := [3]int{1,2,3}
    change(nums)
    fmt.Println(nums)  //[1,2,3]

}
//函数内部无法改变数组元素的值
func change(nums [3]int)  {
    nums[2] = 666
}

二维数组
  • Go语言二维数组格式: var 数组名称[一维数组个数][一维数组元素个数]数组类型
package main

func main() {
    //定义二维数组格式
    var nums [2][3]int = [2][3]int{
        {1,3,5},
        {2,5,6},
    }

    //简单定义方法
    nums := [2][3]int{
        {1,2,3},
        {4,5,6},
    }

    arr := [...][3]int{
        {12,3,5},
        {1,2,6},
    }
    fmt.Println(arr)
   //二维数组也可以省略元素个数,但是只可以省略行数,不可以省略列数
    arr := [...][3]int{
        {12,3,5},
        {1,2,6},
    }

    //遍历二维数组
    for i:=0; i< 2; i++{
        for j:=0;j < 3 ;j++  {
            fmt.Println(arr[i][j])
        }
    }
}

数组的遍历
  • Go语言数组遍历两种方法
    • 普通for循环遍历
    nums := [...]int{2, 3, 5, 1, 3, 6}
      //普通for循环遍历
      for i := 0; i < 6; i++ {
          fmt.Println("index= ", i, "value = ", nums[i])
      }
    
    • for..range遍历
    nums := [...]int{2, 3, 5, 1, 3, 6}
      //高级for循环遍历
      for key,value := range nums{
          fmt.Println(key,"-->",value)
      }
    

Go语言切片

切片
  • 什么是切片

    • 在Go语言中,数组的长度一旦确定就无法改变,为了解决这一问题,推出了一种数据类型切片
    • 切片简单理解就是一个可变长度的数组,底层的实现原理就是一个结构体, 结构体中有一个指针指向了一个数组
      本质上所有的数据都是保存在指向的数组中的
  • 创建切片

    • 通过数组创建切片1
      通过数组来创建
      格式: [起始位置:结束位置], 从起始位置开始截取, 直到结束位置, 但是不包括结束位置
      注意:  截取了多少个元素, len就等于几
             容量等于数组的长度 - 起始位置
      nums := [5]int{1,2,3,4,5}
      //1.通过数组创建切片
      //1.1[起始位置 : 结束位置] 从起始位置开始截取,直到结束位置,但是不包括结束位置索引对应的元素
      var sce []int = nums[2 : 4]
    
      //1.2[: 结束位置]只指定结束位置,不指定起始位置,就是从开始位置截取直到指定的位置,但是也不包括指定位置的元素
      var sce []int = nums[:3]
    
      //1.3[起始位置 : ] 从起始位置开始截取,直到末尾
      var sce []int = nums[0:]
    
      //1.4[: ]只有一个:,从开始位置截取,直到末尾结束
      var sce []int = nums[:]
      fmt.Println(sce)
      //计算切片的长度len当前保存的数据个数
      fmt.Println(len(sce))
      //计算切片的容量cap总共能够保存数据的个数
      fmt.Println(cap(sce))
    
    
    • 通过数组创建切片2
      切片的第三个参数max,不能小于第二个参数,作用是用来控制切片容量的
      //如果指定了第三个参数, 那么切片的容量就等于 第三个参数 - 第一个参数
      //注意点: 如果没有指定第三个参数,那么切片的容量 = 数组的容量 - 第一个参数值
      //        如果指定了第三个参数,那么切片的容量 = 第三个参数 - 第一个参数值
      arr := [7]int{1,2,3,4,5,6,7}
      sce := arr[1:4:4]
      fmt.Println(sce)
      fmt.Println(len(sce))
      fmt.Println(cap(sce))
    
    • 通过make()函数创建切片
     // 2.通过make函数创建切片
      // 第一个参数: 告诉系统要存储什么类型的数据
      // 注意点: 如果是创建切片一定要在传入的数据类型前面写上[]
      // 第二个参数: 告诉系统创建出来的切片len等于多少
      // 第三个参数: 告诉系统创建出来的切片cap等于多少
      // 注意点: 第三个参数可以省略, 如果省略切片的容量就等于切片的长度(等于第二个参数)
      //var sce []int = make([]int, 2, 5)
      var sce []int = make([]int, 2)
      fmt.Println(sce)
      fmt.Println(len(sce))
      fmt.Println(cap(sce))
    
    • 通过语法糖创建切片
      // 3.通过Go提供的语法糖来创建
      // 一定要注意[]里面没有值就是切片
      // 通过Go提供的语法糖来创建len等于cap
      var sce []int = []int{1, 3, 5} // 相当于make([]int, 3)
      fmt.Println(sce)
      fmt.Println(len(sce))
      fmt.Println(cap(sce))
    

切片与数组
  • [ ]没有数字就是切片,有数字就是数组,[...]这种定义格式是数组
  //定义数组
    var arr [5]int = [5]int{1,3,4,5,6}
    var arr = [5]int{1,3,4,5,6}
    arr := [5]int{1,3,4,5,6}
    arr := [...]int{1,3,4,5,6}
//定义二维数组
    var arrs [2][3]int = [2][3]int{
        {1,3,5},
        {2,4,6},
    }
    var arrs = [2][3]int{
        {1,3,5},
        {2,4,6},
    }

    arrs := [2][3]int{
        {1,3,5},
        {2,4,6},
    }

    arrs := [...][3]int{
        {1,3,5},
        {2,4,6},
    }
  //定义切片
    var sce []int = []int{1,3,5}
    var sce = []int{1,3,5}
    sce := []int{1,3,5}
//定义一个切片,切片中保存的是数组
    var sec [][3]int = [][3]int{
        {1, 3, 5},
        {2, 4, 6},
    }

    var sec = [][3]int{
        {1, 3, 5},
        {2, 4, 6},
    }

    sec := [][3]int{
        {1, 3, 5},
        {2, 4, 6},
    }
//定义一个切片,切片中保存切片
    var sec[][]int = [][]int {
        {1, 3, 5},
        {2, 4, 6},
    }

    var sec = [][]int {
        {1, 3, 5},
        {2, 4, 6},
    }
    sec := [][]int {
        {1, 3, 5},
        {2, 4, 6},
    }

append函数
  • append函数格式 :append(切片,数据)
  • append函数作用: 追加切片中的数据
  • append函数注意点
    • 如果通过append函数追加数据之后超过了原有的容量, 那么系统内部会自动按照当前容量*2的方式重新定义一个数组作为切片保存数据的模型
    • 在扩容的时候会重新定义一个新的切片, 所以需要返回一个切片
    • 扩容问题
      • 容量小于1024的时候扩容, 会按照原有容量的2倍扩容
      • 容量大于1024的时候扩容,会按照原有的1/4进行扩容
    sec := make([]int, 1024, 1024)
    sec = append(sec, 6)
    fmt.Println(len(sec))
    fmt.Println(cap(sec))//1280

切片的使用
  • 定义切片
sec := []int{1,3,5,7,9,11}
  • 修改切片中的数据
sec[2] = 666
  • 增加切片中的数据
sec = append(sec, 7)
fmt.Println(sec)
  • 删除切片中指定的数据
//5.删除切片中的指定索引对应的数据
    index := 3
    //不仅可以利用数组获取切片,还可以用切片获取切片
    //sec = sec[:index]
    //fmt.Println(sec) //[1 3 5]
    //sec = sec[index +1 :]
    //fmt.Println(sec) //[9 11]
    //将第二个切片追加到第一个切片后面即可
    sec = append(sec[:index], sec[index +1 :]...)
    fmt.Println(sec) //[1 3 5 9 11]

切片的内存地址
package main

import "fmt"

func main() {
    /*
    通过切片生成切片的注意点
    */

    //1.创建一个数组
    var arr  = [3]int{1,2,3}
    //Go语言中不能通过数组名称获取数组的地址
    //fmt.Printf("%p\n", arr)
    fmt.Printf("%p\n", &arr) //0xc0420500a0
    fmt.Printf("%p\n", &arr[0]) //0xc0420500a0

    //2.通过数组创建一个切片
    //直接打印sce打印的是sce中指针保存的地址,也就是底层指向的那个数组的地址
    sce := arr[:]
    fmt.Printf("%p\n", sce) //0xc0420500a0

    //3.通过切片创建切片
    //通过切片创建一个切片, 新的切片和老的切片底层指向同一个数组
    sce2 := sce[:]
    fmt.Printf("%p\n", sce2) //0xc0420500a0

    //修改数组中的值
    arr[2] = 666
    sce[2] = 666
    sce2[2] = 666
    fmt.Println(arr)
    fmt.Println(sce)
    fmt.Println(sce2)
}
copy函数
package main

import "fmt"

func main() {
    /*
    copy函数的作用是将源切片的值拷贝到目标切片当中
    函数格式 copy(目标切片, 源切片)

     */
    sec1 := []int{1, 2, 3, 6, 9, 10}
    sec2 := make([]int, 2, 5)
    fmt.Println(sec2)
    //将源切片的值拷贝到目标切片当中
    //注意点: 拷贝的时候是以目标切片为准,目标切片中长度为多少将来只能拷贝多少个值进来
    copy(sec2, sec1)
    fmt.Println(sec2)
}

切片与字符串

注意点: 切片和数组不同, 切片不支持== !=操作

package main

import "fmt"

func main() {
    /*
    1.切片可以再生成新的切片, 两个切片底层指向同一个数组
    2.切片和数组不同, 切片不支持== !=操作
    3.在Go语言中字符串的底层实现就是切片, 所以可以通过字符串来生成切片
    */

    //数组可以使用== !=操作
    //arr := [3]int{1,2,3}
    //arr2 := [3]int{4,5,6}
    //arr = arr2
    //fmt.Println(arr)


    var str string = "www.it666.com"
    sec := make([]byte, len(str))
    copy(sec,str)
    fmt.Println(len(str))
    fmt.Printf("%s\n",sec) //www.it666.com
}
切片与数组注意点
  • 数组定义后不初始化,可以使用,切片定义后可以一次性初始化,但是不能逐个初始化,但是可以使用append函数添加数据
  • 数组定义后直接使用
var arr [4]int
    //数组定义后可以直接使用
    arr[0] = 1
    arr[1] = 3
    arr[2] = 5
    arr[3] = 7

    fmt.Println(arr)
  • 切片定义后不能直接使用
    var sce []int
    //不能逐个初始化,会报错
    //sce[0] = 1
    //sce[1] = 3
    //sce[2] = 5

    //可以使用append函数添加数据
    sce = append(sce,1)
    sce = append(sce,3)
    sce = append(sce,5)
    sce = append(sce,7)
    sce = append(sce,9)

    //打印切片
    fmt.Println(sce)
    fmt.Println(len(sce))
    fmt.Println(cap(sce))
  • 计算数组的长度方式
    //计算数组长度的方式
    //第一种方式(推荐)使用len函数
    arr := [4]int{1,3,5,7}
    //length := len(arr)
    //fmt.Println(length)

    //第二种方式,使用unsafe.Sizeof函数计算(不推荐)
    length1 := unsafe.Sizeof(arr)
    length2 := unsafe.Sizeof(arr[0])
    fmt.Println(length1 / length2)
  • 计算切片的长度
    //计算切片的长度
    //第一种方式(推荐)使用len函数
    //注意点: 切片的长度不能使用unsafe.Sizeof函数计算
    //由于切片本质是结构体,所以unsafe.Sizeof计算的是结构体的字节数,不是指向数组的字节数
    sce := []int{1,3,5,6}
    length := len(sce)
    fmt.Println(length)
  • 切片与数组的传递
    • 数组传递是值传递
    • 切片传递是地址(指针)传递
package main

import "fmt"

func main() {
    /*
    1.数组作为函数参数是值传递,在函数内部修改形参是不会影响外部实参的值
    2.切片作为函数的参数是地址传递(指针), 在函数内修改形参, 会影响到函数外的实参
    */
    //arr := [4]int{1,3,4,5}
    //fmt.Println(arr)
    //change1(arr)
    //fmt.Println(arr)

    sce := []int{1,2,3,4}
    fmt.Println(sce)
    change2(sce)
    fmt.Println(sce)
    
}
//数组是值传递
func change1(arr [4]int)  {
arr[0] = 666
}

//切片是地址传递指针
func change2(sce []int)  {
    sce[0] = 666
}


可变参数

  • 可变参数底层实现就是切片
package main

import "fmt"

func main() {
    /*
    可变参数,底层其实就是一个切片
    */
    res := sum(10,20,30)
    fmt.Println(res)

}
//可变参数底层就是一个切片
//注意点: 当一个函数中定义可变参数时候,可变参数只能放在形参列表的最后面
func sum(nums ...int) (res int) {
    for _, value := range nums {
        res += value
    }
    return
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容

  • 数组 和C语言一样,Go语言中也有数组的概念, Go语言中的数组也是用于保存一组相同类型的数据 和C语言一样,Go...
    极客江南阅读 1,199评论 0 2
  • 新手对于数组和切片要如何区分,概念比较模糊,看看下面的说明就懂了 记住,如果在[]运算符里指定了一个值,那么创建的...
    夜空中乄最亮的星阅读 230评论 0 0
  • map(字典、映射) map翻译过来就是字典或者映射, 可以把map看做是切片的升级版切片是用来存储一组相同类型的...
    极客江南阅读 675评论 0 1
  • 逗留法兰克福之时,恰逢其铁人三项比赛。本是清净周末的街头立刻热闹起来。温度高,参与者热情也高,加油助威者热情也高。...
    舒航2018阅读 182评论 0 0
  • 不经意间抬头, 圆月一语道出了繁星, 最亮的那颗星后面是我, 最亮的那颗星是你。 阡陌交错中花落了泪, 泪滴里映着...
    素絢阅读 152评论 3 4