【Go集合数据类型】

数组(Array)

  • 数组是同类元素的集合,它的元素排列在连续的空间中,按下标来标记和访问数组类型定义包括元素类型,数组长度(元素个数)
  • 元素类型相同的两个数组,数组长度不同则类型不同,相互不能复制
  • 数组变量声明后,其元素类型、数组长度均不可变

数组声明

var identifier [n]dataType

    //只声明未赋值
    //数组元素都被初始化为对应类型零值
    var arr1 [5]int
    //声明3个元素的整型数组
    //直接赋值
    arr2 := [3]int{11, 12, 13}
    //声明整型数组
    //直接赋值
    //数组长度由初始化值的数量来确定
    arr3 := [...]int{11, 12, 13, 14, 15} //...不可省略
    //声明4个元素的整型数组
    //对下标为0和3的元素直接赋值
    //其余元素保持零值
    arr4 := [4]int{0: 99, 3: 100}
    fmt.Printf("%v,%v,%v,%v", arr1, arr2, arr3, arr4)
    //[0 0 0 0 0],[11 12 13],[11 12 13 14 15],[99 0 0 100]

数组复制

数组变量之间进行复制时会拷贝整个数组(值拷贝)

    a := [...]string{"USA", "China", "India", "Germany"}
    b := a 
    b[0] = "Singapore"
    fmt.Println("a is ", a)
    fmt.Println("b is ", b) 
    
    //a is [USA China India Germany]  
    //b is [Singapore China India Germany]

数组传参

实参拷贝一份给形参,二者相互独立,传递大数组时效率较低,尽量用指向数组的指针来传参

func changeLocal(num [5]int) {
    num[0] = 55
    fmt.Println("inside function ", num)
}

func main() {
    num := [...]int{5, 6, 7, 8, 8}
    fmt.Println("before passing to function ", num)
    changeLocal(num) //num is passed by value
    fmt.Println("after passing to function ", num)
}
//before passing to function  [5 6 7 8 8]  
//inside function  [55 6 7 8 8]  
//after passing to function  [5 6 7 8 8] 

数组遍历

for 遍历

    a := [...]float64{67.7, 89.8, 21, 78}
    for i := 0; i < len(a); i++ { 
        fmt.Printf("%d th element of a is %.2f\n", i, a[i])
    }

range遍历

    a := [...]float64{67.7, 89.8, 21, 78}
    for i, v := range a { // 第一个参数为序号,第二个为变量
        fmt.Printf("%d the element of a is %.2f\n", i, v)
    }
    //0 the element of a is 67.70  
    //1 the element of a is 89.80  
    //2 the element of a is 21.00  
    //3 the element of a is 78.00

多维数组

    a := [3][2]string{
        {"lion", "tiger"},
        {"cat", "dog"},
        {"pigeon", "peacock"}, //此处,不可忽略,否则报错
    }
    for _, v1 := range a {
        for _, v2 := range v1 {
            fmt.Printf("%s ", v2)
        }
        fmt.Printf("\n")
    }

切片(Slice)

  • 数组的定长性和值拷贝限制其使用
  • 切片封装底层的数组,提供长度可变的数组引用
  • 切片是引用类型,不支持==运算(除了nil)
  • 切片包括三个变量
    • 底层数组指针
    • 切片当前长度
    • 切片容量(小于等于底层数组长度,超过时要变更底层数组)

切片声明

  • 切片声明时,不能给定底层数组大小,否则变成数组声明
  • 声明语法 var identifier [ ]dataType
  • 声明后创建切片变量,但底层数组指针为nil,所以切片变量也为nil
  • 也可使用内置函数make 来声明和初始化,切片底层数组会分配空间,并设置为对应类型零值
    i := make([]int, 5, 5) // 为什么不用构造函数 
    fmt.Println(i)
    // [0 0 0 0 0]

new和make区别

  • new和make是内建的两个函数,主要用来在堆上创建分配类型的内存
  • new用于值类型的内存分配,内存清零,返回该类型指针
  • make用于引用类型如slice、map以及channel的初始化,返回引用

创建切片

指定底层数组创建

     a := [5]int{76, 77, 78, 79, 80}//底层数组
    s1 := a[0:4] // from a[0] to a[3]
    s2 := a[:4]  // from a[0] to a[3]
    s3 := a[2:5] // from a[2] to a[4]
    s4 := a[2:]  // from a[2] to a[4]
    fmt.Printf("%v\n%v\n%v\n%v", s1, s2, s3, s4)
    //[76 77 78 79]
    //[76 77 78 79]
    //[78 79 80]
    //[78 79 80]

同时创建数组和切片

//指定数组大小,只创建数组    
c := [3]int{6, 7, 8}
//不指定数组大小,返回切片引用,底层数组匿名 
d := []int{6, 7, 8}  
//用...推断数组大小,只创建数组 
e := [...]int{6, 7, 8} 

切片长度和容量

内置函数 len() 返回切片当前长度
内置函数cap()返回切片底层数组容量

    arr := [7]int{9, 8, 7, 6, 5, 4, 3}
    sli := arr[1:3]
    fmt.Printf("length of array %d capacity %d\n", len(arr), cap(arr))
    fmt.Printf("length of slice %d capacity %d\n", len(sli), cap(sli))
    //length of array 7 capacity 7
    //length of slice 2 capacity 6  // why 6?

切片共享底层数组

多个切片可共享同一底层数组

    arr := [7]int{9, 8, 7, 6, 5, 4, 3}
    s1 := arr[1:3]
    s2 := arr[1:4]
    arr[1] = 100
    s1[1] = 99
    s2[1] = 88
    fmt.Printf("%v\n", arr)
    fmt.Printf("%v\n", s1)
    fmt.Printf("%v\n", s2)
    //[9 100 88 6 5 4 3]
    //[100 88]
    //[100 88 6]

切片动态增加

内置函数 append() 动态扩展切片,在底层数组容量范围内,会直接覆盖底层数组元素

    arr := [7]int{9, 8, 7, 6, 5, 4, 3}
    sli := arr[1:3]
    sli = append(sli, 20) //增加一个20,切片容量扩展一倍?
    fmt.Printf("%v\n", arr)
    //[9 8 7 20 5 4 3]

切片动态增加时,当超过底层数组容量大小时,会重新创建底层数组,并转移数据
切片增长在元素小于1000时,成倍增长,超过1000,增长速率大概为1.25

切片合并

内置函数 append() 还支持切片的合并,用…运算符把对应切片所有元素都取出

    veggies := []string{"potatoes", "tomatoes", "brinjal"}
    fruits := []string{"oranges", "apples"}
    food := append(veggies, fruits...) //... 不可忽略
    fmt.Println("food:", food)
    //food: [potatoes tomatoes brinjal oranges apples]

切片传参

切片可视为如下的结构体

//$GOROOT/src/runtime/slice.go
type slice struct {
    Length        int
    Capacity      int
    ZerothElement *byte
}

在函数传参时,复制的是结构体拷贝,实现引用传递

多维切片

多维切片比多维数组灵活,每行元素个数不必相同

切片性能

  • 切片引用底层数组,导致底层数组不能被垃圾回收
  • 在底层数组很大,切片很小时,存在明显内存浪费
  • 这时可以用内置函数make()新建目标切片,再用内置函数copy(目标切片,源切片) 实现切片与原较大底层数据的分离

Map

  • Map用于存储一系列无序的键值对
  • 在GO中Map跟数组一样直接使用,无须引用外部库
  • Map也是引用类型,不支持==运算(除了nil)
  • Map的键(key) 只支持值类型(可以使用==、!=运算符作比较)
  • Map的值(value)不限制,但同一Map元素的值类型一致
  • Map 不是线程安全的,不支持并发写

Map初始化

  • Map零值不可用,只声明不初始化为nil值,不分配底层存储空间,不能添加元素
  • 用字面量或make函数进行初始化后可以添加元素
    var m1 map[string]int
    fmt.Println(m1 == nil)
    //true
    //m1["a"] = 1 //error

    m2 := map[string]int{}
    fmt.Println(m2 == nil)
    //false
    m2["a"] = 1 //ok

    m3 := make(map[string]int)
    fmt.Println(m3 == nil)
    //false
    m3["a"] = 1 //ok

元素赋值

可在Map初始化后进行元素赋值
也可在Map初始化时直接元素赋值

    personSalary := make(map[string]int)
    personSalary["steve"] = 12000
    personSalary["jamie"] = 15000
    personSalary["mike"] = 9000
    //初始化时,直接赋值
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }

Mapy元素查找

  • Map元素通过下标直接查找访问
    • 存在对应key的,返回对应value
    • 不存在对应key的,返回value 类型的零值

Map元素通过下标访问其实可以返回两个值(底层实际为函数,Comma-ok 法)
对应的value
对应的key是否存在的布尔值

    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    value, ok := personSalary["joe"]
    if  ok  == true {
        fmt.Println("Salary of joe is", value)
    } else {
        fmt.Println("joe not found")
    }

Map元素操作

  • Map元素可以使用range 遍历,但不保证顺序
    personSalary := map[string]int{
        "steve": 12000,
        "jamie": 15000,
    }
    personSalary["mike"] = 9000
    for key, value := range personSalary {
        fmt.Printf("personSalary[%s] = %d\n", key, value)
    }
    //personSalary[mike] = 9000
    //personSalary[steve] = 12000
    // personSalary[jamie] = 15000
  • 使用内置函数delete()删除Map元素
    • key存在,对应元素被删除
    • key不存在,什么都不发生
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值