go語言之---數組(array)和切片(slice)

1、數組

1.什麼是數組?

  1.數組是一系列同一類型數據的集合html

  2.數組中包含的每一個數據被稱爲數組元素數組

  3.一個數組中包含的元素個數成爲數組長度app

  4.數組的長度是固定的ide

  5.一個數組能夠由零個或者多個元素組成    函數

 

2.數組的申明

var arr [10]int           //10個元素的整型數組

var ptrs [5]*float64  //5個元素的指針數組,每一個指針都指向float64類型 

var points [8]struct{ x, y int }  //8個元素的結構體類型

var arry [2][3]int               //2*3的二維整型數組 

a := [3]int{1, 2, 3} // 長度爲3的數組

b := [5]int{1, 2, 3} //長度爲10,前三個元素爲一、二、3,其它默認爲0

c := [...]int{4, 5, 6} //長度3的方式,Go自動計算長度

r := [...]int{9: 6}    //長度爲10,最後一個元素的值爲6,其它默認爲0

arr2 := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}//二維數組
數組的申明

  在Go語言中,數組長度在定義後就不可更改,在聲明時長度能夠爲一個常量或者一個常量表達式。性能

  

3.數組的初始化

//申明數組
var a [5]byte //長度爲5的數組,每一個元素爲一個字節
var d [2][3]int //二維數組

//初始化數組
a = {'1','2','3'}
d = {{1,2,3},{4,5,6}}
先申明再初始化
a := [3]byte{'1', '2', '3'} //聲明並初始化一個長度爲3的byte數組
a := [...]byte{'1', '2', '3'} //能夠省略長度而採用`...`的方式,Go會自動根據元素個數來計算長度
d := [2][3]int{[3]int{1,2,3},[3]int{4,5,6}}
d := [2][3]int{{1,2,3},{4,5,6}} //若是內部的元素和外部的同樣,那麼上面的聲明能夠簡化,直接忽略內部的
類型
直接申明並初始化

 

4.數組元素訪問

  1.可使用數組下標來訪問數組中的元素spa

  2.數組下標從0開始.net

  3.len(arr)-1則表示最後一個元素的下標3d

package main

import (
    "fmt"

)

func main() {
    var result int
    arr := [...]int{1, 2, 3, 4, 5}

    len := len(arr)   //len獲取數組長度

    fmt.Println("修改前:", arr)

    arr[0] = 100      //下標訪問數組元素

    result = arr[3]    //取出下標爲3的元素並賦值

    fmt.Println("修改後:", arr)

    fmt.Println("數組長度:", len)

    fmt.Println("方位下標爲三的元素:",result)
}


//運行結果
//修改前: [1 2 3 4 5]
//修改後: [100 2 3 4 5]
//數組長度: 5
//方位下標爲三的元素: 4
元素訪問
package main

import(
"fmt"
)

func main(){
    arr := [...]int {9: 1}
    fmt.Println(arr)
    fmt.Println(len(arr))
}

//運行結果
//[0 0 0 0 0 0 0 0 0 1]
//10
計算數組長度
package main

import(
"fmt"
)

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


//運行結果
//arr[0]=1
//arr[1]=2
//arr[2]=3
//arr[3]=4
//arr[4]=5
普通訪問方式,for
package main

import(
"fmt"
)

func main(){
    arr := [5]int {1, 2, 3, 4, 5}
    for i, v := range(arr) {
        fmt.Printf("arr[%d]=%d\n", i, v)
    }
}


//運行結果
//arr[0]=1
//arr[1]=2
//arr[2]=3
//arr[3]=4
//arr[4]=5
經過range訪問

 

5.數組的傳遞

  1.數組做爲函數的參數仍然是值傳遞(值傳遞是複製數組給函數,傳遞後數組跟原數組沒有關係)指針

  2.雖然可使用數組的指針來代替,可是改變不了數組長度。(能夠改變數組內的值,可是不能改變數組的長度)

package main

import "fmt"

func main() {
    arr1 := [5]int{1, 2, 3, 4, 5}
    fmt.Println("交換前arry1= " ,arr1)

    swap(arr1 )
    
    fmt.Println("交換後arry1= " ,arr1)

    }
func swap(a [5]int)  {
    arr3 := a
    fmt.Println("值傳遞交換前arr3= ",arr3)

    c := arr3[0]
    arr3[0] = arr3[4]
    arr3[4] = c
    fmt.Println("值傳遞交換後arr3= ",arr3)

}

//運行結果
//交換前arry1=  [1 2 3 4 5]
//值傳遞交換前arr3=  [1 2 3 4 5]
//值傳遞交換後arr3=  [5 2 3 4 1]
//交換後arry1=  [1 2 3 4 5]
數組的值傳遞
package main

import "fmt"

func main() {
    arr1 := [5]int{1, 2, 3, 4, 5}
    fmt.Println("交換前arry1= " ,arr1)

    swap_pointer(&arr1 )

    fmt.Println("交換後arry1= " ,arr1)

    }

func swap_pointer(a *[5]int)  {
    var arr3 *[5]int
    arr3 = a
    fmt.Println("指針傳遞交換前arr3= ",arr3)

    c := arr3[0]
    arr3[0] = arr3[4]
    arr3[4] = c
    fmt.Println("指針傳遞交換後arr3= ",arr3)
}

//運行結果
//交換前arry1=  [1 2 3 4 5]
//指針傳遞交換前arr3=  &[1 2 3 4 5]
//指針傳遞交換後arr3=  &[5 2 3 4 1]
//交換後arry1=  [5 2 3 4 1]
數組的指針傳遞

 

6.數組的比較

  1.若是數組元素的類型是可比較的,那麼這個數組也是可的比較

  2.只有數組的全部元素都相等數組纔是相等的。

  3.因爲長度也是數組類型的一部分,因此長度不一樣的數組是不等的。

  4.數組可遍歷、可修改,是否可比較,由數組元素決定。

  5.%T用於顯示一個值對應的數據類型。

 

7.數組的侷限性

  1.數組的長度在定義以後沒法修改。

  2.數組是值類型,每次傳遞都將產生一份副本。

  3.顯然這沒法知足開發者的某些需求。

2、切片(slice)

1.什麼是切片?

  1.切片(Slice)是一個擁有相同類型元素的可變長度的序列。

  2.Go語言切片的內部結構包含地址、大小和容量。

  3.切片通常用於快速地操做一塊數據集合。

  4.slice 老是指向底層的一個 array。

  5.slice自己不是數組,slice 是一個指向 array的指針。

              切片結構和內存分佈示意圖

 

2. 從數組或者一個切片中生成一個切片        

   slice [開始位置:結束位置:容量]

    a. slice 表示目標切片對象

    b. 開始位置對應目標切片對象的索引

    c. 結束位置對應目標切片的結束索引

package main

import "fmt"

func main() {

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

    fmt.Println("c的長度爲:%d",len(c))
    fmt.Println("c的容量爲:%d",cap(c))
    fmt.Printf("c的類型:%T",c)
}


//運行結果
//c的長度爲:%d 3
//c的容量爲:%d 4
//c的類型:[]int
從數組或切片中生成切片

   從數組或切片生成新的切片擁有以下特性

    a.取出的元素數量爲:結束位置-開始位置

    b.取出元素不包含結束位置對應的索引,切片最後一個元素使用 slice[len(slice)] 獲取

    c.當缺省開始位置時,表示從連續區域開頭到結束位置

    d.當缺省結束位置時,表示從開始位置到整個連續區域末尾

    e.二者同時缺省時,與切片自己等效

    f.二者同時爲0時,等效於空切片,通常用於切片復位

    (ps:根據索引位置取切片 slice 元素值時,取值範圍是(0~len(slice)-1),超界會報運行時錯誤。生成切片時,結束位置能夠填寫 len(slice) 但不會報錯。)

3.直接申明新切片

  每一種類型均可以擁有其切片類型,表示多個類型元素的連續集合。

var name []T

//name 表示切片類型的變量名。
//T 表示切片類型對應的元素類型。
package main

import "fmt"

func main() {

    // 聲明字符串切片
    var strList []string
    // 聲明整型切片
    strList = []string{"asa","esd"}
    var numList []int
    // 聲明一個空切片
    numListEmpty := []int{1,2,3}
    // 輸出3個切片
    fmt.Println(strList, numList, numListEmpty)
    // 輸出3個切片大小
    fmt.Println(len(strList), len(numList), len(numListEmpty))
    // 切片斷定空的結果
    fmt.Println(strList == nil)
    fmt.Println(numList == nil)
    fmt.Println(numListEmpty == nil)

}

//運行結果
//[asa esd] [] [1 2 3]
//2 0 3
//false
//true
//false
直接聲明新的切片

  ps:  1. 切片是動態結構,只能與nil斷定相等,不能互相判等。

    2. 聲明新的切片後,可使用append() 函數來添加元素。    

 

4.使用 make() 函數構造切片

  語法:

    make( []T, size, cap )

      T:切片的元素類型

      size:就是爲這個類型分配多少個元素

      cap:預分配的元素數量,這個值設定後不影響 size,只是能提早分配空間,下降屢次分配空間形成的性能問題

package main

import "fmt"

func main() {

    a := make([]int, 2)
    b := make([]int, 2, 10)
    fmt.Println(a, b)
    fmt.Println(len(a), len(b))


}


//運行結果
//[0 0] [0 0]
//2 2
使用make函數建立切片

  1. a 和 b 均是預分配 2 個元素的切片,只是 b 的內部存儲空間已經分配了 10 個,但實際使用了 2 個元素。

  2. 容量不會影響當前的元素個數,所以 a 和 b 取 len 都是 2。  

 

(ps:使用 make() 函數生成的切片必定發生了內存分配操做。但給定開始與結束位置(包括切片復位)的切片只是將新的切片結構指向已經分配好的內存區域,設定開始與結束位置,不會發生內存分配操做。)

 

五、使用append向切片追加單個元素

  1.append() 能夠爲切片動態添加元素。

  2.每一個切片會指向一片內存空間,這片空間能容納必定數量的元素。

  3.當空間不能容納足夠多的元素時,切片就會進行「擴容」。

  4.「擴容」操做每每發生在 append() 函數調用時。

package main

import "fmt"

func main() {
        //聲明一個整型切片。
    var numbers []int
       
    for i := 0; i < 10; i++ {
                //循環向 numbers 切片添加10個數。
        numbers = append(numbers, i)
                //打印輸出切片的長度、容量和指針變化。使用 len() 函數查看切片擁有的元素個數,使用 cap() 函數查看切片的容量狀況
        fmt.Printf("len: %d  cap: %d pointer: %p\n", len(numbers), cap(numbers), numbers)
    }
}

//運行結果
//len: 1  cap: 1 pointer: 0xc00001c060
//len: 2  cap: 2 pointer: 0xc00001c090
//len: 3  cap: 4 pointer: 0xc000016120
//len: 4  cap: 4 pointer: 0xc000016120
//len: 5  cap: 8 pointer: 0xc00001e180
//len: 6  cap: 8 pointer: 0xc00001e180
//len: 7  cap: 8 pointer: 0xc00001e180
//len: 8  cap: 8 pointer: 0xc00001e180
//len: 9  cap: 16 pointer: 0xc000088000
//len: 10  cap: 16 pointer: 0xc000088000                                
append時,切片擴容分析

  a.len() 函數並不等於 cap。

  b.當元素個數超過cap()的數量時,切片會進行擴容

  c.擴容後切片的內存地址發生改變

  d.可是切片的名稱沒有發生改變。

 

六、使用append向切片中追加多個元素/其餘切片

package main

import "fmt"

func main() {

    var car []string

    // 添加1個元素
    car = append(car, "OldDriver")

    // 添加多個元素
    car = append(car, "Ice", "Sniper", "Monk")
    // 添加切片
    team := []string{"Pig", "Flyingcake", "Chicken"}
    car = append(car, team...)
    fmt.Println(car)
    
}

//運行結果
//[OldDriver Ice Sniper Monk Pig Flyingcake Chicken]
append追加多個元素

  在team後面加上了...,表示將 team 整個添加到 car 的後面。

相關文章
相關標籤/搜索