Golang 数组与切片

 

数组

- 介绍:

数组是同一类型元素的集合。
Go 语言中不允许混合不同类型的数据;
数组的个数也是数组类型的一部分,换句话来说,数组中的元素的数量是固定的,等同于python中的元组 注意: 如果是
interface{} 类型数组,可以包含任意类型

 

- 声明数组:

  - 数组的表现形式: [n]T ;

    - n: 表示数组中元素的数量;

    - T:表示每个元素的类型;

    - 声明数组后,若不初始化,则会将所有的元素全部赋值为该类型的零值;

  - 示例:

package main

import (
    "fmt"
)

func main() {
    var a [3]int //int array with length 3
    fmt.Println(a)
}

// 打印内容:[0 0 0]

 

- 数组赋值:

  - 根据索引赋值:

  - 示例:

package main

import (
    "fmt"
)

func main() {
    var a [3]int       //int array with length 3
    a[0] = 12         // array index starts at 0
    a[1] = 78
    a[2] = 50
    fmt.Println(a)
}
// 打印内容: [12 78 50]

 

  - 简略声明,且初始化赋值:

    - 在简略声明中,不需要将全部的元素都进行赋值,Go 会自动将多余的元素赋值为零值;

    - 示例:

package main

import (
    "fmt"
)

func main() {
    a := [3]int{12, 78, 50} // short hand declaration to create array
    fmt.Println(a)
}

// 打印内容:[12 78 50]

 

  - 忽略数组长度,声明数组:

    - 语法: [...]T{a,b,c}

    - Go 的编译器会自动计算数组的长度;

    - 示例:

package main

import (
    "fmt"
)

func main() {
    a := [...]int{12, 78, 50} // ... makes the compiler determine the length
    fmt.Println(a)
}

// 打印内容:[12 78 50]

 

- 数组的类型问题:

  - 数组是值类型;

    - 当数组赋值给一个新的变量时,该变量会得到一个原始数组的一个副本。对新变量进行更改,不会影响原始数组;

    - 示例:

 1 // 示例1:
 2 
 3 package main
 4 
 5 import "fmt"
 6 
 7 func main() {
 8     a := [...]string{"USA", "China", "India", "Germany", "France"}
 9     b := a // a copy of a is assigned to b
10     b[0] = "Singapore"
11     fmt.Println("a is ", a)
12     fmt.Println("b is ", b) 
13 }
14 // 打印内容:
15     a is [USA China India Germany France]  
16     b is [Singapore China India Germany France]
17 
18 
19 // 示例2:
20 package main
21 
22 import "fmt"
23 
24 func changeLocal(num [5]int) {
25     num[0] = 55
26     fmt.Println("inside function ", num)
27 }
28 func main() {
29     num := [...]int{5, 6, 7, 8, 8}
30     fmt.Println("before passing to function ", num)
31     changeLocal(num) //num is passed by value
32     fmt.Println("after passing to function ", num)
33 }
34 
35 // 打印内容:
36     before passing to function  [5 6 7 8 8]
37     inside function  [55 6 7 8 8]
38     after passing to function  [5 6 7 8 8]
示例

 

  - 数组的长度也是决定类型的一部分,不同长度的数组不能相互赋值:

    - 数组不能调整大小,等同于python中的元组;

package main

func main() {
    a := [3]int{5, 78, 8}
    var b [5]int
    b = a // not possible since [3]int and [5]int are distinct types
}
// 报错信息:cannot use a (type [3]int) as type [5]int in assignment。

 

- 函数len() ; 将数组传进去,即可获取数组的长度:

  - 示例: 

package main

import "fmt"

func main() {
    a := [...]float64{67.7, 89.8, 21, 78}
    fmt.Println("length of a is",len(a))
}

// 打印内容:length of a is 4

   

range循环

- for 循环 range 方式。 它将返回索引和该索引处的值:

  - 示例:

package main

import "fmt"

func main() {
    a := [...]float64{67.7, 89.8, 21, 78}
    sum := float64(0)
    for i, v := range a {//range returns both the index and value
        fmt.Printf("%d the element of a is %.2f\n", i, v)
        sum += v
    }
    fmt.Println("\nsum of all elements of a",sum)
}
// %.2f: 格式化代替浮点数

// 打印内容:
    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

    sum of all elements of a 256.5

 

切片

- 介绍:

切片是由数组建立的一种方便、灵活且功能强大的包装(Wrapper)。
切片本身不拥有任何数据。它们只是对现有数组的引用。
切片的长度是切片中的元素数。切片的容量是从创建切片索引开始的底层数组中元素数; 某种角度上来讲,这里的切片类同于python中的列表;

 

- 创建一个切片:

  - 语法: []T

  - 该语法和数组创建的类似,不过,中括号中不需要加点点点,就是切片;

  - 切片对应的值: 切片对应的值,应当是已有的数组的值;

    - 语法:a[start:end]

  - 以上两种语法的示例:

 1 // 示例1
 2 package main
 3 
 4 import (
 5     "fmt"
 6 )
 7 
 8 func main() {
 9     a := [5]int{76, 77, 78, 79, 80}
10     var b []int = a[1:4] // creates a slice from a[1] to a[3]
11     fmt.Println(b)
12 }
13 
14 // 打印内容:[77 78 79]
15 
16 
17 // 示例2:
18 package main
19 
20 import (  
21     "fmt"
22 )
23 
24 func main() {  
25     c := []int{6, 7, 8} // 创建一个有 3 个整型元素的数组,并返回一个存储在 c 中的切片引用
26     fmt.Println(c)
27 }
28 
29 // 打印内容:
示例

  

- 使用make 创建切片:

  - 语法: make([]T,len,cap); 

    - []T: 类型;

    - len:长度;

    - cap:容量;可选传参,默认值为切片长度

    - make 函数创建一个数组,并返回引用该数组的切片。

    - 示例:

package main

import (
    "fmt"
)

func main() {
    i := make([]int, 5, 5)
    fmt.Println(i)
}

// 打印内容:[0 0 0 0 0]

 

- 切片的修改:

  - 切片本身不具有数据,切片中的数据,都是底层的数组,也就是说,当切片中的数据发生修改时,底层的数组中值也会发生变化;

  - 示例:

package main

import (
    "fmt"
)

func main() {
    numa := [3]int{10, 12, 16}
    num1 := numa[:]
    num1[0] = 100
    fmt.Println(num1)
    fmt.Println(numa)

}
// 打印内容:

    [100 12 16]
    [100 12 16]

 

- 追加切片元素: 

  - 切片因为由数组支持,且数组本身的长度是固定的;所以,在切片追加元素的时候,实际创建了一个新的数组,并且将旧的数组的值复制到新的数组中,同时将切片的容量也翻了一倍

  - append(切片,数据); 有返回值,需要被接收,不然会报错

  - 示例:

package main

import (
    "fmt"
)

func main() {
    numa := [3]int{10, 12, 16}
    num1 := numa[:]
    num1[0] = 100
    fmt.Println(num1, cap(num1))
    num1 = append(num1, 17)
    fmt.Println(num1, cap(num1))

}

// 打印内容:
    [100 12 16] 3
    [100 12 16 17] 6

 

  

- 多维切片:

package main

import (
    "fmt"
)

func main() {  
     pls := [][]string {
            {"C", "C++"},
            {"JavaScript"},
            {"Go", "Rust"},
            }
    for _, v1 := range pls {
        for _, v2 := range v1 {
            fmt.Printf("%s ", v2)
        }
        fmt.Printf("\n")
    }
}

// 打印内容:
    C C++  
    JavaScript  
    Go Rust

 

- 内存优化:

  -问题描述:

切片持有对底层数组的引用;
只要切片在内存中,数组就不能被垃圾回收。

当数组很大,但是我们只需要利用一部分的数据做切片;
这时候的数组不会被回收,很占用内容;

  - 解决方法:

    - 利用 copy() 备份需要使用的切片:

    - 示例:

 1 package main
 2 
 3 import (
 4     "fmt"
 5 )
 6 
 7 func countries() []string {
 8     countries := []string{"USA", "Singapore", "Germany", "India", "Australia"}
 9     neededCountries := countries[:len(countries)-2]
10     countriesCpy := make([]string, len(neededCountries))
11     copy(countriesCpy, neededCountries) //copies neededCountries to countriesCpy
12     return countriesCpy
13 }
14 func main() {
15     countriesNeeded := countries()
16     fmt.Println(countriesNeeded)
17 }
18 
19 // 解析:
20     neededCountries := countries[:len(countries)-2 创建一个去掉尾部 2 个元素的切片 countries
21      11 行,将 neededCountries 复制到 countriesCpy 同时在函数的下一行返回 countriesCpy
22     现在 countries 数组可以被垃圾回收, 因为 neededCountries 不再被引用。

 

posted @ 2018-10-28 18:43  浮生凉年  阅读(255)  评论(0编辑  收藏  举报