Go语言数组和切片

此处数组只讲Go语言中和C语言不一样的地方

  • 格式不同:
    Go语言定义数组的格式:var ages [3]int

定义的同时初始化

格式 var 数组名称 数组类型 = 数组类型{值}

var ages [3]int = [3]int{1,3,5}
  • 注意点:
    1.在定义的同时初始化必须在大括号前写上数据类型,并且数据类型必须相同(数组长度和数据类型)

    2.可以和C语言一样部分初始化,但是C语言部分初始化没有被赋值的地方保存了垃圾数据,Go语言中没有被赋值的地方默认为0\

    3.数组中数组的名称不能代表数组的地址


  • 第二种方式(省略数组长度)
ages := [...]int{1,3,5}
  • 在这里用...表示数组长度,编译器根据赋值的元素个数自动计算数组的元素个数

先定义后初始化

var ages [3]int
ages = [3]int{1,3,5}
  • 在这里,Go语言可以一次性给数组赋值,当然也可以逐个赋值

数组注意点

  1. Go语言中数组是值类型,数组之间的赋值是值拷贝,而不是地址的拷贝
ages := [3]int{1,3,5}
change(ages)
fmt.println(ages)//1,3,5


func change(num [3]int) {
    num[1] = 666
}

2.由于数组是值类型,所以两个数组间可以用" == " " != "进行比较,但是进行值比较的数组必须类型长度完全相同,完全相同!!!


数组的遍历

  • 方法一: 传统的for循环
  • 方法二: for index,value := range ages{
    fmt.println(index,value)
    }

二维数组

  • 定义二维数组的格式
    var 数组名称 [行数][列数]数据类型
    var 数组名称 [一维数组的个数][每个一维数组的元素个数]数据类型
  • 注意点:
    二维数组也可以省略元素个数, 但是只能省略行数, 不能省略列数

切片(重点)

  • 数组的长度一旦固定,就不能改变,Go语言为了解决这一问题,产生了切片,切片就是可变的数组
  • 切片的底层是结构体
    Go语言源码中如此展示
type slice struct{
      array unsafe.Pointer // 指向底层数组指针
      len int // 切片长度(保存了多少个元素)
      cap int // 切片容量(可以保存多少个元素)
    }

创建切片的方式

  • 方法一: 通过数组来创造切片

    • 格式:[起始位置:结束位置] 包括起始位置但不包括结束位置,左闭右开的区间
    • 注意点:
      • 切片的长度(len)等于截取到的数组的长度

      • 切片的容量(cap)等于数组的长度减去切片的起始位置

      • 如果不写起始位置,就是从第0个开始截取

      • 如果不写结束位置,就是截取到末尾

var ages[5] = [5]int{1,3,5,7,9}
var sce[] = ages[2:]
fmt.println(sce)//[5,7,9]
fmt.println(len(sce))//3
fmt.println(cap(sce))//3

var sce2[] = ages[:2]
fmt.println(sce2)//[1,3]
fmt.println(len(sce2))//2
fmt.println(cap(sce2))//5

  • 方法二: 通过make函数创建
    • 格式:make([]数据类型,长度,容量)

      1. 第一个参数: 创建的数据类型,创建切片前一定要加[]

      2. 第二个参数: 告诉系统创建切片的长度

      3.第三个参数: 告诉系统创建切片的容量(如果第三个参数不写,那么第三个长度默认和切片的长度相等)

var sce []int = make([]int, 2)
    fmt.Println(sce)//[0,0]
    fmt.Println(len(sce))//2
    fmt.Println(cap(sce))//2

  • 方法三: 通过Go语言提供的语法糖创建
    • 中括号没有值就是切片
    • 特点:用Go语法糖创建的切片的长度和容量相等
    • var ages []int = []int{1,3,5,7,9}

切片的使用

  • 使用方法一: 切片是可变长度的数组,所以可以像数组一样使用切片,但是索引的长度不能超过切片的len
var sce []int = make([]int,2,5)
sce[2] = 999//报错,索引大于切片长度
fmt.println(sce)
  • 使用方法二: 可以通过预先定义好的函数来使用切片

    • append函数
    • append(切片,数据)

    • append函数作用是在切片len后面添加数据

  • 注意点:

    • 在append函数后面追加的数据超过了切片的cap,那么切片会按照当前容量*2的方式重新扩容,并且sce[0]的值和扩容前的值相等,说明将源切片拷贝了一份作为新切片,切片的地址会发生改变

    • append函数返回一个切片,由于append扩容的时候需要创建一个新的切片,所以返回一个切片

    • 如果容量不超过1024时,扩容的时候会按照cap*2扩容,如果容量超过1024,扩容的时候会按照原来cap的1/2扩容

    • 如果append追加的数据未超过切片的cap,虽然返回一个切片,但是切片的地址没有改变,如果append追加的数据超过了切片的cap,那么返回的切片的地址会发生改变

var sce []int = make([]int, 2, 3)
fmt.Printf("%p\n",sce)//0xc0420520c0
sce = append(sce, 3)
fmt.Printf("%p",sce)//0xc0420520c0


var sce2 []int = make([]int, 2, 2)
fmt.Printf("%p\n",sce)//0xc0420080c0
sce = append(sce2, 3)
fmt.Printf("%p",sce2)//0xc04200e300
  • 使用方法三:
    • 切片的增删改查
      • 增(append函数)

      • 改(切片名称[索引] = 值)


      • for _,value in range 切片名称{
        if value == 3 {
        fmt.Println("包含数字3")
        }
        }

          • 我们不仅可以通过数组创建切片,还能通过切片创建切片
          • 通过切片创建的切片,两个切片指向同一个数组
          • 切片的删就是将第二次截取的切片添加到第一次截取的切片后面即可
          • append(sce[:index],sce[index+1:])
var ages []int = []int{1,3,5,7,9,11}
//假如需要删掉的索引是3(值为7)
var sce []int = ages[:3]
var sce2 []int = ages[4:]
sce3 = append(sce,sce2)
fmt.Println(sce)//[1,3,5,9,11]

数组和切片的辨别

  • 只要定义的时候中括号里有东西,哪怕是...,那定义的就是数组不是切片

切片和函数

  • 可变参数的函数,其中可变参数底层原理就是切片
  • 注意点: 如果函数编写了可变参数, 那么可变参数只能放在形参列表的最后
    res:=sum(10, 20, 30)
    fmt.Println(res)//60
}

// 注意点: 如果函数编写了可变参数, 那么可变参数只能放在形参列表的最后
func sum(nums ...int) int{
//func sum(value float32, nums ...int) int{
    var res int
    for _,value := range nums {
        res += value
        fmt.Println(value)
    }

    return res
}
func sum(nums []int) int{
    // 2.遍历切片
    var res int
    for _, value := range nums{
        res += value
    }
    return res
}

  • copy函数
    • copy(目标切片, 源切片)

    • 注意点:

      • 如果目标切片的容量大于了源切片的容量,那么源切片会一一将数据覆盖到目标切片上

      • 如果目标切片的容量小于了源切片的容量,那么源切片会一一将数据覆盖到目标切片上,多余的数据会被剔除

    sce1 := []int{1, 3} // 源切片
    sce2 := []int{2, 4, 6} // 目标切片
    fmt.Println(sce2)
    copy(sce1, sce2)
    fmt.Println(sce1)//[2,4]

切片的注意点

1.切片可以再生成新的切片, 两个切片底层指向同一个数组

2.切片和数组不同, 切片不支持== !=操作

3.在Go语言中字符串的底层实现就是切片, 所以可以通过字符串来生成切片

//需求:将字符串"www.it666.com"的首字母改为M
var str string = "www.it666.com"
sce := make([]byte,len(str))
copy(sce,str)
sce[0] = 'M'
fmt.Printf("%s\n", sce)
  1. 通过数组创建切片补充

    格式: 数组名称[low: high: max]

    注意点:

    • max必须大于第二个参数

    • 如果max不写,那么cap就等于数组长度 - 第一个参数

    • 如果写上max,那么cap就等于max - 第一个参数

var arr [6]int = [6]int{1,3,5,7,9,11}
var sce []int = arr[2:4:4]
fmt.Println(sce) // [5,7]
fmt.Println(len(sce)) // 2
fmt.Println(cap(sce)) // 2
  1. 仅仅定义, 没有初识的数组是可以使用的, 但是仅仅定义但是没有初始化的切片是不能使用的
var sce []int
//sce[0] = 666  编译报错
//sce[1] = 888  编译报错
sce = make([]int, 3, 5)
sce[0] = 666
sce[1] = 888
sce[2] = 999
fmt.Println(sce) // [666,888,999]
var sce []int
sce = append(sce, 1)
sce = append(sce, 2)
sce = append(sce, 3)
fmt.Println(sce) // [1,2,3]
  1. 切片计算长度不能用unsafe.Sizeof(sce),切片本质是一个结构体,所以Sizeof实际上计算的是结构体的内存,在64位机上为24
    var sce []int = []int{1, 3, 5, 7, 9}
        //推荐方式:
        length := len(sce)
        fmt.Println(length)

数组和切片作为函数参数的区别

  • 数组作为函数参数,是值传递,函数内改变不会改变实参的值

  • 切片作为函数参数,是地址传递,函数内改变会改变实参的值

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

推荐阅读更多精彩内容