• Go通关04:正确使用 array、slice 和 map!


    Array(数组)

    数组存放的是固定长度、相同类型的数据。

    数组声明

    1. var <数组名> = [<长度>]<元素>{元素1,元素2}
      var arr = [2]int{1,2}
      或者
      arr := [2]int{1,2}

    2. var <数组名> = [...]<元素类型>{元素1,元素2}
      var arr = [...]int{1,2}
      或者
      arr := [...]int{1,2}

    3. var <数组名> = [...]<类型>{索引1:元素1,索引2:元素2}
      var arr = [...]int{1:1,0:2}
      或者
      arr := [...]int{1:1,0:2}

    数组的每个元素在内存中都是连续存放的,每个元素都有一个下标,下标从0开始。
    数组长度可以省略,会自动根据{}中的元素来进行推导。
    没有初始化的索引,默认值是数组类型的零值。

    数组循环

    for i,v := range array {
      fmt.Printf("索引:%d,值:%s
    ",i,v)
    }
    
    1. range 表达式返回数组索引赋值给 i,返回数组值赋值给 v。
    2. 如果返回的值用不到,可以用 _ 下划线丢弃:
    for _,v:= range array{
      fmt.Printf("值:%s
    ",i,v)
    }
    

    切片

    切片和数组类型,可以理解为动态的数组,切片是基于数组实现的,它的底层就是一个数组。对于数组的分割,便可以得到一个切片。

    数组生成切片

    slice := array[start:end]

    array := [5]string{"a","b","c","d","e"}
    slice := array[2:5]
    fmt.Println(slice) //[c d e]
    

    注意:这里包含索引2,但是不包含索引5的元素,即:左闭右开。
    经过切片后,切片的索引范围也改变了。
    array[start:end] 中的 start 和 end 都是可以省略的,start 的默认值是 0 ,end 的默认值为数组的长度。

    array[:] 等价于 array[0:5]
    

    切片修改

    切片的值也可以被修改,这里也可以证明切片的底层是数组。

    array := [5]string{"a","b","c","d","e"}
    slice := array[2:5] //[c d e]
    slice[1] = "f"
    fmt.Println(slice) //[c f e]
    fmt.Println(array) //[a b c f e]
    

    修改切片,对应的数组值也被修改了,所以证明基于数组的切片,使用的底层数组还是原来的数组,一旦修改切片的元素值,底层数组对应的值也会被修改。

    切片声明

    使用 make 函数声明切片

    //声明一个元素类型为string的切片,长度是4
    slice := make([]string,4)
    //长度是4,容量是8
    slice1 := make([]srting,4,8)
    

    切片的容量不能比切片长度小。
    长度就是元素个数。
    容量就是切片的空间。

    上面实例在内存上划分了一个容量为8的内存空间,但是只是用了4个内存空间,剩余的处于空闲状态。当通过 append 往切片追加元素时,会追加到空闲内存上,剩余空间不足时,会进行扩容。

    字面量初始化切片

    slice2 := []string{"a","b","c"}
    fmt.Println(len(slice2),cap(slice2)) //3 3
    

    Append

    append 函数对一个切片进行追加元素:

    slice3 := append(slice2,"d")
    //追加多个元素
    slice3 := append(slice2,"d","f")
    //追加一个切片
    slice3 := append(slice2,slice...)
    

    小技巧:
    在创建新切片时,最好让长度和容量一样,这样追加操作的时候就会生成新的底层数组,从而和原有数组分离,就不会因为公用底层数组导致修改内容的时候影响多个切片。

    切片循环

    切片循环与数组一样,也是使用 for range 方式。

    Map (映射)

    map 是一个无序的 k-v 键值对集合。其中 k 必须是相同类型。k 和 v 的类型可以不同。 k 的类型必须支持 == 比较运算符,这样才可以判断它是否存在,并保证唯一

    Map 声明初始化

    1. make:
      mapName := make(map[string]int)

    2. 字面量:
      mapName := map[string]int{"无尘":29}

    如果不想创建的时候添加键值对,使用空大括号{}即可,切记不能省略。

    Map 获取、删除

    //添加键值对或更新对应的key的value
    mapName["无尘"] = 20
    //获取指定key的value
    age := mapName["无尘"]
    

    获取不存在的 k-v 键值对时,如果 key 不存在,返回的 value 是该值的零值,所以很多时候,需要先判断 map 中的 key 是否存在。

    nameAge := make([string]int)
    nameAge["无尘"]=29
    age,ok := nameAge["无尘"]
    if ok {
      fmt.Println(age)
    }
    
    • map 的 [] 操作返回两个值
      • 第一个是 value
      • 第二个是标记该 key 是否存在,存在则为 true

    delete()函数进行删除

    delete(nameAge,"无尘")

    • delete 有两个参数,一个是map,一个是要删除的 key 。

    遍历 Map

    nameAge["无尘"] = 29
    nameAge["无尘1"] = 30
    nameAge["无尘2"] = 31
    
    for k,v := range nameAge{
      fmt.Println("key is",k,"value is ",v)
    }
    
    • 对应 map ,for range 返回两个参数,分别是 k 和 v。

    小技巧:for range 遍历 map 的时候,若使用一个返回值,则这个返回值是 map 的 key 。

    Map 的大小

    map 不同于切片,map 只有长度,没有容量。可以使用 len 函数获取 map 大小。

    String 和 []byte

    字符串也是一个不可变的字节序列,可以直接转为字节切片 []byte :

    s:="Hello无尘小生"
    bs := []byte(s)
    

    string 不止可以直接转为 []byte,还可以使用 [] 操作符获取指定索引的字节值。

    字符串是字节序列,每一个索引对应一个字节,在 UTF8 编码下,一个汉字对应三个字节。
    如果把一个汉字当做一个长度计算,可以使用 utf8.RuneCountInString 函数。
    for range 遍历时,是按照 unicode 字符进行循环的,一个汉字占一个长度。

  • 相关阅读:
    运维
    Linux学习
    .net Core使用Knife4jUI更换Swagger皮肤
    VS Code中使用live Server
    去重复保留一条数据
    sql server 索引检测
    Centos 7 .Net core后台守护进程Supervisor教程
    鼠标移动 在左边放大图片
    根据配置表将数据从A表转入B表
    JS替换或切割
  • 原文地址:https://www.cnblogs.com/isungge/p/15095006.html
Copyright © 2020-2023  润新知