1. 程式人生 > >Go語言學習筆記(五)-其他型別(指標、結構體、、)

Go語言學習筆記(五)-其他型別(指標、結構體、、)

指標

在Go語言中也存在指標,且指標儲存了變數的地址,初始值為nil。定義指標與定義變數相似,不同的是在型別前面指標需要加*例如:

var p *int   //此處定義了一個int型別的指標

指標也可以通過已有變數獲取,通過&操作符便可,與C語言相似Go中*指標名指向變數底層,但是不同的是Go中沒有指標運算。示例程式碼如下:

package main
import "fmt"
func main(){
    i,j := 10,1000
    var p *int //定義一個int指標
    p = &i  //從i變數中獲取指向i的指標並賦值給p
    fmt.Println(i)
    *p = 21
//修改p指標指向的底層儲存的資料 fmt.Println(i) p = &j *p = *p/10 fmt.Println(j) }

結構體

結構體就是一些欄位的集合,通過type來宣告定義型別,並用struct來宣告結構體。具體實現如下:

package main
import "fmt"
type TestType struct{
    x int
    y int
}
func main(){
    p := TestType{1,2}
    fmt.Println(p)
    p.x = 4
    fmt.Println(p)
}

從上述示例程式碼中可以看出結構體的欄位通過點號來訪問。
結構體還可以通過指標來訪問,若一個結構體指標為p那麼我們可以通過(&p).x來呼叫結構體的欄位或者使用隱式間接引用,直接寫p.x就可以。結構體文法可以通過直接列出欄位的值來新分配一個結構體,也可以通過Name:語法列出部分欄位。

陣列

型別[n]T表示擁有n個T型別的值得陣列。陣列的長度是陣列的一部分,所以陣列不能改變大小。
為了解決這個限制,Go推出了切片這一型別,切片為陣列元素提了供動態大小,靈活的視角,比陣列更實用。切片通過[]T來定義。切片不儲存任何資料,它只是描述了底層陣列中的一段,或者我們也可以理解為切片其實相當於對資料中的一段的每一個元素都獲取了一個指標物件存放到另一陣列中。建立陣列與切片的方法如下:

package main
import "fmt"
func main(){
    //建立一個數組並設定初始值Go自動推導型別
    myArray := [10]int{1,2,3,4,5,6,7,8,9,10}
    fmt.Println(myArray)
    //建立一個數組設定初始值
    var myArray1 [5]int = [5]int{6,5,4,3,2}
    fmt.Println(myArray1)
    //建立一個切片初始元素個數為5,預設值為0,預留10個儲存空間
    mySlice := make([]int,5,10)
    fmt.Println(mySlice)
    //從陣列上直接建立一個切片,初始元素個數與陣列相同
    mySlice2 := []int{1,2,3,4,5}
    fmt.Println(mySlice2)
    //穿件一個切片元素個數為6預設值為0
    mySlice3 := make([]int,6)
    fmt.Println(mySlice3)
}

通過make方式來建立的切片也是建立動態陣列的方法。
在進行切片時,可以利用它的預設行為來忽略上下界,切片的下界預設為0,上界為該切片的長度。例如:

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

以上四個切片是等價的

切片擁有容量與長度兩個屬性,長度就是包含的元素個數,容量就是從第一個元素開始到底層陣列元素的末尾的個數,長度與容量分別用len(s)和cap(s)來獲取。切片的零值為nil,nil切片的容量與長度為0,且沒有底層陣列。
切片可以包含任何型別,包括切片。
切片可以通過append來追加元素,該函式為自建函式,使用方式如下:

package main
import "fmt"
func main(){
    var s []int
    printSlice(s)
    //輸出len=0 cap=0 []
    //追加一個元素
    s = append(s,0)
    printSlice(s)
    //輸出len=0 cap=0 []
    //追加多個元素
    s = append(s,2,3,4,5)
    printSlice(s)
    //輸出len=1 cap=1 [0]
}
func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

上述程式碼展示了append的兩種使用方式,新增一個元素與新增多個元素

對映(map)

對映就是將鍵對映到值,對映的零值為nil,nil既沒有鍵也不能新增鍵,make函式會返回給定型別的對映,並將其初始化備用。對映的文法與結構體相似,但是對映必須要有鍵名。若頂級型別只有一種型別,那麼可以在文法元素中忽略。

package main

import "fmt"

type Vertex struct {
    Lat, Long float64
}

var m = map[string]Vertex{
    "Bell Labs": {40.68433, -74.39967},
    "Google":    {37.42202, -122.08408},
}

func main() {
    fmt.Println(m)
    //輸出map[Bell Labs:{40.68433 -74.39967} Google:{37.42202 -122.08408}]

    //修改Bell Labs對應的元素
    m["Bell Labs"] = Vertex{2000,-74.39967}
    fmt.Println(m)
    //輸出map[Bell Labs:{2000 -74.39967} Google:{37.42202 -122.08408}]

    //刪除Bell Labs對應的元素
    delete(m,"Bell Labs")
    fmt.Println(m)
    //輸出map[Google:{37.42202 -122.08408}]

    //通過雙賦值來判斷鍵是否存在
    v, ok := m["Google"]
    fmt.Println("The value:", v, "Google?", ok)
    //輸出The value: {37.42202 -122.08408} Google? true
}

range

for迴圈的range形式可以遍歷切片也可以遍歷對映,for迴圈遍歷切片時,每次遍歷都會返回兩個值,一個是元素的下標一個是元素的副本,通過_可以將下標或者值忽略,當只需要下標時可以直接去掉,value部分。

package main

import (
    "golang.org/x/tour/wc"
    "strings"
)

func WordCount(s string) map[string]int {
    res := make(map[string]int)
    strs := strings.Fields(s)
    for _,v:= range strs{
        res[v]++
    }
    return res
}

func main() {
    wc.Test(WordCount)
}

函式值與閉包

Go中函式也是值,也可以作為引數或者返回值。Go函式可以是一個閉包。閉包是一個函式值,它引用了其函式體之外的變數。該函式可以訪問並賦予其引用的變數的值,換句話說,該函式被“繫結”在了這些變數上。

package main

import "fmt"

func main() {
    var j int = 5
    //此處建立了一個匿名函式,返回值為函式值,並通過匿名函式後跟()來執行這個匿名函式將返回的函式值賦值給a變數
    a := func()(func()){
        var i int = 10
        return func(){
            fmt.Printf("i,j: %d , %d\n",i,j)
        }
    }()
    a()
    j *= 2
    a()
}