Go基础学习三之数组array、切片slice、map

前端之家收集整理的这篇文章主要介绍了Go基础学习三之数组array、切片slice、map前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

Go编程语言:支持并发、垃圾回收的编译型系统级编程语言!本文主要是按照无闻的《Go 编程基础》开源视频学习并记录笔记。

一、数组Array

  • 定义数组的格式:var<varName>[n]<type> (n>=0,n表示数组元素个数)
  • 数组长度也是类型的一部分,因此具有不同长度的数组为不同类型
  • 注意区分指向数组的指针指针数组
  • 数组在Go中为值类型
  • 数组之间可以使用==或!=进行比较,但不可以使用< 或 >
  • 可以使用new来创建数组,此方法返回一个指向数组的指针
  • Go支持多维数组

示例:

package main


import "fmt"  

func main() {
  // var a [2]int
    a := [2]int{1,2}
    
    fmt.Println(a)
}

打印结果:

[1 2]

new 创建数据

// var a [2]int
    a := [10]int{}
    a[1] = 2
    fmt.Println(a)

    p := new([10]int)
    p[1] = 2
    fmt.Println(p)

打印结果:

➜  run arr.go
[0 2 0 0 0 0 0 0 0 0]
&[0 2 0 0 0 0 0 0 0 0]

看一下,上边有什么不同吗?第二行结果带了一个地址符&

多维数组

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

  fmt.Println(a)

打印结果:

[[1 2 3] [4 5 6]]

冒泡排序法:

package main


import "fmt"  

// 冒泡排序
func main() { 

  // ...可以表示不确定的元素数
  a := [...]int{1,4,9,20,13,3}
  fmt.Println(a)

  // 计算数组的长度
  num := len(a)
  for i := 0; i < num; i++ {

      // 外边的循环,每循环一次,会将最大的值排在前边
      for j := i + 1; j < num; j++ {
          if a[i] < a[j] {
              temp := a[i]
              a[i] = a[j]
              a[j] = temp
          }

      }

  }

    fmt.Println(a)
}

打印结果:

[1 4 9 2 5 0 20 13 3]
[20 13 9 5 4 3 2 1 0]

二、切片Slice

  • 其本身并不是数组,它指向底层的数组
  • 作为变长数组的替代方案,可以关联底层数组的局部或全部
  • 引用类型
  • 可以直接创建或从底层数组获取生成
  • 使用len()获取元素个数,cap()获取容量
  • 一般使用make创建
  • 如果多个slice指向相同底层数组,其中一个的值改变会影响全部
  • make([]T,len,cap)
  • 其中cap可以省略,则和len的值相同
  • len表示存数的元素个数,cap表示容量

示例:

package main


import "fmt"  

func main() {
    // var s1 []int;
    a := [10]int{1,3,6,7,8,9}
    fmt.Println(a)

    s1 := a[5:10]  // a[5,9]  注意:包含5,不包含10[)
    fmt.Println(s1)

}

打印结果:

➜  myfirstgo go run slice.go
[1 2 3 4 5 6 7 8 9 0]
[6 7 8 9 0]

创建切片:

// 第一个参数表示数组类型,第二个参数表示元素个数,第三个参数表示容量,先分配10个连续的内存,如果不设置容量默认为元素个数
s1 := make([]int,10)  
fmt.Println(len(s1),cap(s1))

打印结果:

➜  myfirstgo go run slice.go
3 10

Reslice,即再次slice

  • Reslice时索引以被slice的切片为准
  • 索引不可以超过被slice的切片的容量cap()值
  • 索引越界不会导致底层数组的重新分配而是引发错误
a := []byte{'a','b','c','d','e','f','g','h'}
    sa := a[2:5]
    sb := sa[1:3]

    fmt.Println(sb)          // 打印出:[100 101]
    fmt.Println(string(sb))  // 打印出:de

如果sb的数组下标越界:

a := []byte{'a','h','i','j'}
    sa := a[2:5]
    fmt.Println(sa)  
    fmt.Println(len(sa),cap(sa))   // 打印sa的元素个数和容量

    sb := sa[3:5]   // 超过sa的下标
    // fmt.Println(sb)  
    fmt.Println(string(sb))

打印结果:

➜  myfirstgo go run slice.go
[99 100 101]
3 8
[102 103]
fg

slice 指向一个连续的内存块,如,我们取一个数组的前几个元素,则实际它取得是前几个元素的地址,我们可以根据地址拿到未取到的数组元素,是不是和其他语言比,很神奇啊

Append

  • 可以在slice尾部追加元素
  • 可以将一个slice追加在另一个slice尾部
  • 如果最终长度未超过追加到slice的容量则返回原始slice
  • 如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据
s1 := make([]int,6)
    fmt.Printf("%p\n",s1) // 打印出内存地址: 0xc420016180

    s1 = append(s1,1,3)
    fmt.Printf("%v %p\n",s1,s1) // 打印出内存地址:0xc420016180

    s1 = append(s1,s1) // 打印出内存地址:0xc420066060

打印结果:

➜  myfirstgo go run slice.go
0xc420016180
[0 0 0 1 2 3] 0xc420016180
[0 0 0 1 2 3 1 2 3] 0xc420066060

由以上我们可以看到,如果追加的数组元素超过其容量,则会分配一个新的地址给这个数组,原来的会被干掉。

Copy

s1 := []int{1,5}
 s2 := []int{7,9}

// 拷贝s2的元素到s1中
 copy(s1,s2)
 // copy(s2,s1)
 fmt.Println(s1)

打印结果:

[7 8 9 4 5]

三、map(集合)

Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。

  • 类似其他语言中的哈希表或者字典,以key-value形式存储数据
  • Key必须是支持==或!=比较运算的类型,不可以是函数、map或slice
  • Map查找比线性搜索快得多,但比使用索引访问数据的类型慢100倍
  • Map使用make()创建支持 := 这种简写方式
  • make([keyType]valueType,cap),cap表示容量,可省略
  • 超出容量时会自动扩容,但尽量提供一个合理的初始值
  • 使用len()获取元素个数
  • 键值对不存在时自动添加,使用delete()删除某键值对
  • 使用 for range 对map和slice进行迭代操作

1、定义 Map

可以使用内建函数 make 也可以使用 map 关键字来定义 Map:

/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对

举例:

package main


import "fmt"  

func main() {

    // 声明map变量
    // var m map[int]string

    // m = map[int]string{}
    // m = make(map[int]string)

     m := make(map[int]string)

    // 赋值
     m[1] = "love"

     // 删除
     delete(m,1)

    fmt.Println(m) 
}

打印:

➜  myfirstgo go run map.go
map[]

多个map嵌套:

var m map[int]map[int]string
     m = make(map[int]map[int]string)
     a,ok := m[2][1]
     if !ok {
         m[2] = make(map[int]string)
     }
     m[2][1] = "MeiM"
     a = m[2][1]
    
    fmt.Println(a,ok)

打印:

➜  myfirstgo go run map.go
MeiM false

迭代

sm := make([]map[int]string,5)
     for _,v := range sm {
         v = make(map[int]string,1)
         // 此处的v为拷贝,而不是引用,不会改变原值
         v[1] = "OK"
         fmt.Println(v)
     }

     fmt.Println(sm)

打印:

➜  myfirstgo go run map.go
map[1:OK]
map[1:OK]
map[1:OK]
map[1:OK]
map[1:OK]
[map[] map[] map[] map[] map[]]

2、小试牛刀

根据for range 用法,尝试将类型为 map[int]string 的键和值进行交换,变成类型为 map[string]int

需要转换为下面的例子:

m1 := map[int]string{1:"a",2:"b",3:"c"}
m2 := map[string]int{"a":1,"b":2,"c":3}

示例:

m1 := map[int]string{1:"a",3:"c"}
     // m2 := map[string]int{"a":1,"c":3}

    m2 := make(map[string]int)

     for key,v := range m1 {
          // fmt.Println(key)
          // fmt.Println(v)
         m2[v] = key

     }

     fmt.Println(m2)

打印结果:

➜  myfirstgo go run map.go
map[a:1 b:2 c:3]
原文链接:https://www.f2er.com/go/187909.html

猜你在找的Go相关文章