zoukankan      html  css  js  c++  java
  • Golang: 数组和切片

    数组

    同其他语言一样,数组是一些相同类型的元素的集合。数组声明

    数组的类型为 n[T],其中 n 表示数组中元素的个数,T 表示数组中元素的类型。数组元素的个数 n 也是数组类型的一部分

    1 package main
    2 
    3 import "fmt"
    4 
    5 func main() {
    6     var a [5]int //int array a and   length is 5
    7     fmt.Println(a)
    8 }
    var a [5]int 是我们常用的一种声明数组的方式。同时也会给数组种的所有元素赋值int的初始值0.运行代码我们得到:[0 0 0 0 0]

    我们还可以用shorhand 速记声明的方式声明和赋值数组:
    1 package main
    2 
    3 import "fmt"
    4 
    5 func main() {
    6     a := [5]int{1, 3, 4, 5, 6} //int array a and   length is 5
    7     fmt.Println(a)
    8 }

    这个代码的运行结果是:[1 3 4 5 6]

    如果没有给所有的元素赋值,那么后面的元素会被赋予默认值。

    在声明数组的时候,可以使用...来代替数组长度,编译器会帮我们计算数组长度

    1 package main
    2 
    3 import "fmt"
    4 
    5 func main() {
    6     a := [...]int{1, 3, 6} //int array a and   length is 3
    7     fmt.Println(len(a))
    8 }

    这个代码的运行结果是3,表明编译器帮我们计算好了数组长度。

    由于数组的长度属于数组类型的一部分,那么[3]int和[5]int 不是相同一类型,不可以相互赋值。

    数组遍历

    Go提供了for rang来让我们遍历数组,这样比用for 循环简洁一些。

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     a := [...]string{"a", "b"}
     7 
     8     for i, v := range a { //range returns both the index and value
     9         fmt.Printf(" the element %d of a is %s 
    ", i, v)
    10     }
    11 }

    上面的代码运行结果是:

    the element 0 of a is a
    the element 1 of a is b 

    切片

    由于数组长度不可变,导致数组的应用场景大幅减少。还好Go给我们提供了切片。

    把上面的代码稍微修改一下,我们来创建一个切片

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     a := [...]string{"a", "b", "c", "d", "e"}
     7 
     8     for i, v := range a { //range returns both the index and value
     9         fmt.Printf(" the element %d of a is %s 
    ", i, v)
    10     }
    11 
    12     b := a[2:3]
    13     fmt.Println(b)
    14 }

    运行结果是

     the element 0 of a is a 
     the element 1 of a is b 
     the element 2 of a is c 
     the element 3 of a is d 
     the element 4 of a is e 
    [c]

    我们通过 a[start:end] 这样的语法创建了一个从 a[start] 到 a[end -1] 的切片。在上面代码中,我们用这种方式创建了长度为1 的切片b。

    我们还可以使用和创建数组相似的方式来创建切片

    1 package main
    2 
    3 import "fmt"
    4 
    5 func main() {
    6     b := []string{"a", "b", "c", "d", "e"}
    7     fmt.Println(b)
    8 }

    需要注意的是[]中间是没有长度或者...的。这段代码创建了一个切片b,然后代码的运行结果是:[a b c d e]

    切片的长度和容量

    切片的长度就是切片中元素的个数。切片的容量是 切片创建的数组的长度减去创建切片时的start值。

    具体我们看代码

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     a := [...]string{"a", "b", "c", "d", "e"}
     7     b := a[1:2]
     8     fmt.Printf("length of slice %d capacity %d", len(b), cap(b)) //length is 1 and capacity is 4
     9 
    10 }

    运行结果是:length of slice 1 capacity 4

    append 追加数据到切片上

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     a := [...]string{"a", "b", "c", "d", "e"}
     7     b := a[1:2]
     8     fmt.Printf("length of slice %d capacity %d
    ", len(b), cap(b)) //length is 1 and capacity is 4
     9     b = append(b, "x", "y", "z", "m", "n")
    10     fmt.Printf("length of slice %d capacity %d
    ", len(b), cap(b)) //length is 1 and capacity is 8
    11 
    12 }

    第8行代码给切片b追加了5个元素,那么长度就是6,长度超过了容量4,go是怎么做的?如果容量超了,go会创建一个新的数组,容量翻倍,然后返回新数组的完整切片。

    代码的运行结果是

    length of slice 1 capacity 4
    length of slice 6 capacity 8

    我们还可以使用append把一个切片完整的追加到一个切片上:

     1 package main
     2 
     3 import "fmt"
     4 
     5 func main() {
     6     a := []string{"a", "b"}
     7     b := []string{"c", "d", "e"}
     8     a = append(a, b...)
     9     fmt.Println(a)
    10 }

    运行结果是:

    [a b c d e]

    这里有点类似ES6的写法

    var arr = [1, 2, 3];
    
    var arr1 = [...arr, 4, 5, 6]; 

    切片是数组的一种外层表示,所以我们每次修改切片,最终都会将修改落到数组上。

    但是这时候再修改切边,修改就不会再反应到原来的数组上。

    make创建切片

    我们还可以使用函数make来创建切片。func make([]T, len, cap) []T,其中cap参数是可选的。

    1 package main
    2 
    3 import "fmt"
    4 
    5 func main() {
    6     a := make([]int, 3)
    7     fmt.Println(a)
    8 
    9 }

    切片和数组作为参数传递

    先上两段代码,第一段:

    package main
    
    import "fmt"
    
    func main() {
        a := []string{"a", "b", "c", "d", "e"}
        fmt.Println("before call function:", a)
        changeZeroElementA(a)
        fmt.Println("after call function:", a)
    
        b := [5]string{"a", "b", "c", "d", "e"}
        fmt.Println("before call function:", b)
        changeZeroElementB(b)
        fmt.Println("after call function:", b)
    }
    
    func changeZeroElementA(arr []string) {
        //arr = []string{"X", "Y"}
        arr[0] = "changed"
    }
    func changeZeroElementB(arr [5]string) {
        arr[0] = "changed"
    }

    结果是:

    before call function: [a b c d e]
    after call function: [changed b c d e]
    before call function: [a b c d e]
    after call function: [a b c d e]

    第二段:

    package main
    
    import "fmt"
    
    func main() {
        a := []string{"a", "b", "c", "d", "e"}
        fmt.Println("before call function:", a)
        changeZeroElementA(a)
        fmt.Println("after call function:", a)
    
        b := [5]string{"a", "b", "c", "d", "e"}
        fmt.Println("before call function:", b)
        changeZeroElementB(b)
        fmt.Println("after call function:", b)
    }
    
    func changeZeroElementA(arr []string) {
        arr = []string{"X", "Y"}
        arr[0] = "changed"
    }
    func changeZeroElementB(arr [5]string) {
        arr[0] = "changed"
    }

    运行结果:

    1 before call function: [a b c d e]
    2 after call function: [a b c d e]
    3 before call function: [a b c d e]
    4 after call function: [a b c d e]

    看到这里是不是有些奇怪,其实go里面一切都是值传递。这里有全方面的解释:https://stackoverflow.com/questions/39993688/are-golang-slices-pass-by-value

    切片是数组的一种外层表示,所以我们每次修改切片,最终都会将修改落到数组上。

  • 相关阅读:
    UVa 10010 Where's Waldorf?
    boost 学习笔记
    C++ enum类型的一个更好的用法
    新浪面试题:删除字符串中多余的空格
    微软面试题:写程序找出二叉树的深度
    c++中sizeof的分析
    复习计划
    boost学习之 时间和日期 timer
    c++ template学习总结3
    微软面试题:反序一个单向链表
  • 原文地址:https://www.cnblogs.com/13579net/p/10101006.html
Copyright © 2011-2022 走看看