暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Golang避坑系列 - 数组&切片&map 你真的会吗

Golang开发 2021-08-09
298

头条真实面试题

new 和 make 区别

make
返回的还是引用类型本身;而new
返回的是指向类型的指针。


make
也是用于内存分配的,但是和new
不同,它只用于chan
map
以及slice
的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。

注意,因为这三种类型是引用类型,所以必须得初始化,但是不是置为零值,这个和new
是不一样的。

 

二者都是内存的分配(堆上),但是make
只用于slice、map以及channel的初始化(非零值);而new
用于类型的内存分配,并且内存置为零。



数组 Arrays

数组是同一种数据类型的固定长度的序列。

数组是值类型,因此改变副本的值,不会改变本身的值;

当作为方法的入参传入时将复制一份数组而不是引用同一指针。

通过从0开始的下标索引访问元素值。


数组定义

    var a []int
    a = make([]int, 5)
    var a1 [5]int = [5]int{1, 2, 3, 4, 5} //len:5 content:[1 2 3 4 5]
    var a2 = [5]int{1, 2, 3, 4, 5} //len:5 content:[1 2 3 4 5]
    var a3 = [...]int{1, 2, 3, 4, 5} //len:5 content:[1 2 3 4 5]
    var a4 = [...]int{1: 100, 2: 200} //len:3 content:[0 100 200]
    var a5 = [...]string{1"nick"2"dawn"//len:3 content:[ nick dawn]


    数组定义后,长度不能变。

    长度是数组类型的一部分,具有不同长度的数组,其类型是不同的。

    因此,var a[5] int 和 var a[9]int 是不同的类型。


    数组使用

    通过下标访问,超出会报错

      arr := [5]int{1, 2, 3}
      //fmt.Println(arr[5]) 报错


      通过for遍历数组元素

        func main()  {
        arr := [5]int{1, 2, 3}
        for i:=0; i<len(arr); i++ {
        fmt.Println(arr[i]) //12300
        }
        for i,v := range arr{
        fmt.Printf("index[%d]:content[%v]\n", i, v)
        }
        }


        值类型数组赋值,改变副本不会改变自身

          func main()  {
          arr := [5]int{1, 2, 3}
          arr2 := arr
          arr2[0] = 10
          fmt.Println(arr) //[1 2 3 0 0]
          fmt.Println(arr2) //[10 2 3 0 0]
          }


          栗子 斐波那契数列

            func test1(n int) {
            var a []int
            a = make([]int, n)


            a[0] = 1
            a[1] = 1


            for i := 2; i < n; i++ {
            a[i] = a[i-1] + a[i-2]
            }
            for _, v := range a {
            fmt.Println(v)
            }
            }



            二维数组 

            多维数组,二维数组举例

              var a1 [2][5]int


              二维数组遍历

                func main() {
                var a1 [2][5]int = [...][5]int{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}


                for row, v := range a1 {
                for col, v1 := range v {
                fmt.Printf("(%d,%d)=%d ", row, col, v1)
                }
                fmt.Println()
                }
                }



                切片 Slices

                切片是长度可变、容量固定的相同的元素序列。

                切片是数组的一个引用,因此切片是引用类型

                因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。

                slice 与 array 接近,但是在新的元素加入的时候可以增加长度。slice 总是指向底层的一个 array。slice本身不是数组,slice 是一个指向 array的指针。


                切片定义 

                创建切片跟创建数组唯一的区别在于 Type 前的“ [] ”中是否有数字,为空,则代表切片,否则则代表数组。

                  s1 := [] int{1, 2, 3}          //直接初始化切片,[]表示是切片类型,初始化值依次是1,2,3.其cap=len=3
                  s2 := arr[:] //初始化切片s2,是数组arr的引用
                  s3 := arr[startIndex:endIndex] //将arr中从下标startIndex到endIndex-1下的元素创建为一个新的切片
                  s4 := arr[startIndex:] //缺省endIndex时将表示一直到arr的最后一个元素
                  s5 := arr[:endIndex] //缺省startIndex时将表示从arr的第一个元素开始
                  s6 := s1[startIndex:endIndex] //通过切片s6初始化切片截取s1
                  s7 := make([]int, len, cap) //通过内置函数make()初始化切片s,cap可以省略(省略时,值等同于len)


                  len() 与 cap()

                  长度是指已经被赋过值的最大下标+1,可通过内置函数len()获得。

                  容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。

                    arr := [5]int{1, 2, 3}
                    fmt.Println(len(arr)) //5
                    fmt.Println(cap(arr)) //5


                    切片使用

                    遍历及修改

                      for i, v := range slice0 {
                      slice0[i] = strings.ToUpper(v)
                      fmt.Printf("index[%d]content[%s,%s]\n", i, v, slice0[i])
                      }


                      append 及 copy

                      append操作:slice可以在尾部追加元素,甚至还可以将一个slice追加到另一个slice的尾部,如果最终的长度没有超过原始的slice,那么append操作将返回原来的slice,否则将重新分配内存地址。

                      copy操作:copy操作返回复制的元素的个数,复制的数量是len(src)和len(dst)中最小的值。


                        slice := []int{1, 2}
                        fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[2],content:[1 2]
                        slice = append(slice, 5, 6, 8, 9)
                        fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[6],content:[1 2 5 6 8 9]


                        slicecp := make([]int, len(slice))
                        fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[6],content:[1 2 5 6 8 9]
                        n := copy(slicecp, slice)
                        fmt.Printf("len[%d],content:%v, retN:%d\n", len(slice), slice, n) //len[6],content:[1 2 5 6 8 9], retN:6
                        slicecp[0] = 10
                        fmt.Printf("len[%d],content:%v\n", len(slice), slice) //len[6],content:[1 2 5 6 8 9]
                        fmt.Printf("len[%d],content:%v\n", len(slicecp), slicecp) //len[6],content:[10 2 5 6 8 9]


                        sliceN := append(slice, slicecp...)
                        fmt.Printf("len[%d],content:%v\n", len(sliceN), sliceN) //len[12],content:[1 2 5 6 8 9 10 2 5 6 8 9]


                        值类型修改值会影响本身。

                          slice0 := []string{"a", "b", "c", "d", "e"}
                          slice1 := slice0
                          slice1[0] = "Nick"
                          fmt.Println(slice0) //[Nick b c d e]
                          fmt.Println(slice1)    //[Nick b c d e]



                          内存布局与扩容

                          切片是引用类型,指针内部只向一个数组。

                           代码实现,内存地址表示是同一块地址。

                            func main() {
                            var a []int = []int{1, 2, 3, 4, 5}
                            s := a[1:]
                            fmt.Printf("a=%p, s=%p \n", &(a[1]), s) //a=0xc420016188, s=0xc420016188
                            s = append(s, 10, 10, 10)
                            fmt.Printf("a=%p, s=%p \n", &a[1], s) //a=0xc420016188, s=0xc4200141c0
                            }


                            切片的长度是可变的,那自动扩容是怎样的机制呢?

                            是 double(双倍),看下面代码。

                              unc main() {
                              var a [5]int = [...]int{1, 2, 3, 4, 5}
                              s := a[1:]
                              fmt.Println(cap(s), len(s)) //4 4
                              s = append(s, 10, 10, 10)
                              fmt.Println(cap(s), len(s)) //8 7
                              s = append(s, 10)
                              fmt.Println(cap(s), len(s)) //8 8
                              s = append(s, 10)
                              fmt.Println(cap(s), len(s)) //16 9
                              s = append(s, 10, 10, 10, 10)
                              fmt.Println(cap(s), len(s)) //16 13
                              s = append(s, 10, 10, 10, 10, 10, 10)
                              fmt.Println(cap(s), len(s)) //32 19
                              }



                              map

                              map在Go语言中是作为一种内建类型存在。

                              key-value的数据结构,又叫字典或关联数组。

                              map是引用类型

                              map声明是不会分配内存的,需要make初始化。


                              map声明初始化

                              声明

                                var a map[keytype]valuetype
                                var a map[string]string
                                var a map[string]int
                                var a map[int]string
                                var a map[string]map[string]string  //嵌套


                                 声明并初始化

                                  var a map[string]string
                                  a = make(map[string]string, 10)


                                  a := make(map[string]string, 10)
                                  a := make(map[string]string)


                                  var a map[string]string = map[string]string{}
                                  var a map[string]string = map[string]string{
                                  "A": "A",  //注意是逗号
                                  }


                                  map 使用

                                  增删改查

                                    m["name"] = "Nick"    "create"
                                    delete(m, "name") "delete"
                                    m["name"] = "Dawn" "update"
                                    name := m["name"] "read"


                                    读取不异常

                                      name, errbool := m["name"]
                                      if !errbool {
                                      m["name"] = "Nick"
                                      }


                                      二维map

                                        func modify(a map[string]map[string]string) {
                                        _, ok := a["name"]
                                        if !ok {
                                        a["name"] = make(map[string]string)
                                        }
                                            a["name"]["Nick"] = "suolong"
                                        a["name"]["Nicky"] = "manyRou"
                                        }


                                        func testMap3() {
                                        var a map[string]map[string]string
                                        a = make(map[string]map[string]string, 10) //初始化一维
                                        a["name"] = make(map[string]string) //初始化二维


                                        modify(a)
                                        fmt.Println(a)
                                        }


                                        slice of map

                                          Items := make([]map[int][int], 5)
                                          For i := 0; i < 5; i++ {
                                          items[i] = make(map[int][int])
                                          }


                                          map 排序

                                          1. 先获取所有key,把key进行排序

                                          2.  按照排序好的key,进行遍历

                                            import "sort"


                                            func testMapSort() {
                                            var a map[int]int
                                            a = make(map[int]int, 5)


                                            a[8] = 10
                                            a[5] = 10
                                            a[2] = 10
                                            a[1] = 10
                                            a[9] = 10


                                            var keys []int
                                            for k, _ := range a {
                                            keys = append(keys, k)
                                            }


                                            sort.Ints(keys)


                                            for _, v := range keys {
                                            fmt.Println(v, a[v])
                                            }
                                            }



                                            map 反转

                                            初始化另外一个map,把key、value互换即可

                                              func testMapSort1() {
                                              var a map[string]int
                                              var b map[int]string


                                              a = make(map[string]int, 5)
                                              b = make(map[int]string, 5)


                                              a["name"] = 53
                                              a["ege"] = 10


                                              for k, v := range a {
                                              b[v] = k
                                              }


                                              fmt.Println(b)
                                              }


                                              文章转载自Golang开发,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                              评论