Go:學習筆記兼吐槽(3) Go:學習筆記兼吐槽(1) Go:學習筆記兼吐槽(2) Go:學習筆記兼吐槽(3)

 

 

Go:學習筆記兼吐槽(1)

Go:學習筆記兼吐槽(2)

Go:學習筆記兼吐槽(3)

 

 


 

數組

Golang 中,數組是值類型。

數組的聲明

var arr [10]int

數組的初始化

var arr1 [3]int = [3]int{123}
var arr2 = [3]int{456}
var arr3 = [...]int{789}
var arr4 = [...]int{110022003300}

用 for-range 遍歷數組

基本語法:

for index, value := range 數組變量{
}

其中:index 爲數組下標,value 是該下標位置的值。

長度是數組類型的一部分

長度是數組類型的一部分,就是說數組不可以脫離長度而存在。聽起來不太明白,我們來看下面的一個示例就明白了,這真的是一個大坑。

假設,我們現在要寫一個排序函數,C# 中,我們會這樣定義:

public void Sort(int[] array)
{
}

但是,在 Golang 中,這是不行的。

func main() {
    var arr [3]int = [3]int{123}
    Sort(arr)
}

func Sort(array []int){
}

Sort(arr) 這句編譯就會報錯:cannot use arr (type [3]int) as type []int in argument to Sort。因爲 Sort 函數的參數 array []int 是一個切片,不是數組,將數組作爲參數傳給 Sort 就會報類型不匹配。

如果一定需要以數組作爲參數傳遞,Sort 的參數必須定義成數組,就是帶上長度:

func Sort(array [3]int){
}

這麼定義這函數還有啥用?吐槽一萬字…
雖然有切片可以用來實現我們的功能,但是,數組就變得有點雞肋了。

切片 slice

切片是引用類型,類似於 C# 中的 list 。內部維護一個數組,當追加元素超出切片容量時,切片自動擴容。(跟 list 是一樣的機制。)

切片的聲明

var arr []int

切片的使用

//方法一:
var arr1 [5]int = [5]int{12345}
slice1 := arr1[13]    //這裏的使用跟 Python 很像

//方法二:
var slice2 []int = make([]int510)

//方法三:
var slice3 []int = []int{12345}

使用 make 初始化切片,make 的三個參數依次爲:切片數據類型,切片長度,切片容量。

給切片追加元素

//方法一:追加一個或多個同類型
var slice1 []int = make([]int510)
slice1 = append(slice1, 100200)
fmt.Printf("%v\n", slice1)

//方法二:追加切片(只能是切片,不可以是數組)
var slice2 []int = []int{12345}
slice1 = append(slice1, slice2...)    // 三個點不能少
fmt.Printf("%v", slice1)

append 函數也很搞笑,其返回值必須賦值給一個切片,否則編譯都過不了。如果一個切片調用 append 追加元素後,又賦值給了自己(我們一般也是這麼用的),則切片的地址不會發生改變(除非發生了擴容)。如果 切片 1 調用 append 後賦值給了 切片 2,則 切片 1 保持未追加前的原樣不變,另生成一個新的切片賦給 切片 2

示例:

var slice1 []int = make([]int510)
fmt.Printf("%v %p\n", slice1, &slice1)    // [0 0 0 0 0] 0xc000004460

slice1 = append(slice1, 100)
fmt.Printf("%v %p\n", slice1, &slice1)    // [0 0 0 0 0 100] 0xc000004460

slice2 := append(slice1, 200)
fmt.Printf("%v %p\n", slice1, &slice1)    // [0 0 0 0 0 100] 0xc000004460
fmt.Printf("%v %p\n", slice2, &slice2)    // [0 0 0 0 0 100 200] 0xc0000044e0

映射 map

就是字典。

map 的聲明

var m map[int]string

map 的使用

// 方式一:使用 make 函數
m := make(map[int]string10)

// 方式二:直接賦值
m := map[int]string{
    1"張三",
    2"李四",
}

make 方法的第一個參數是 map 的數據類型,第二個參數是初始容量。

注意,如果是方式二直接賦值,最後一個 key-value 後面也要加逗號。

刪除元素

delete(map, key)

參數:

  • map:要刪除元素的 map
  • key:要刪除的 key,當 key 在 map 中不存在時,不進行任何操作,也不報錯。

Golang 中 map 沒有類似其他語言中的 clear 方法,如果要一次性刪除全部元素,可遍歷 map 逐一刪除,或者重新 make 一下使其指向一個新的內存空間。

查找元素

val, finded := m[1]
if finded{
    fmt.Println(val)
}

遍歷元素

只能用 for-range 遍歷

for k, v := range m{
    fmt.Printf("%v: %v\n", k, v)
}

結構體 struct

  • Golang 中沒有類(class),Go 中的結構體(struct)和其他語言中的類有同等的地位。可以理解爲 Golang 是基於 struct 來實現面向對象。
  • Golang 中面向對象編程非常簡潔,去掉了傳統 OOP 語言中的繼承、方法重載、構造函數、析構函數、隱藏的 this 指針等等。
  • Golang 仍然有面向對象編程的封裝、繼承、多態的特性,只是實現方式和其他 OOP 語言不一樣。
  • 結構體是值類型。結構體的所有字段在內存中是連續的。

結構體的聲明

type 結構體名稱 struct{
    field1 type
    field2 type
}

p1 := Person{}
p1.Name = "Tom"
p1.Age = 10

// 或者
p2 := Person{"Jerry"5}

結構體的使用

type Person struct{
    Name string
    Age int
}

結構體指針

// 方式一:
var person1 *Person = new(Person)
(*person1).Name = "Tom"
(*person1).Age = 10
fmt.Println(*person1)

// 方式二:
person2 := new(Person)
person2.Name = "Tom"
person2.Age = 10
fmt.Println(*person2)

// 方式三:
var person3 *Person = &Person{"Jerry"5}
fmt.Println(*person3)

這三種方式定義的都是結構體指針,因爲是指針,所以給字段賦值的標準方式應該是方式一的寫法,但是 Go 的設計者爲了程序員使用方便,給出了一個語法糖,使 (*person1).Name = "Tom" 簡化爲 person1.Name = "Tom",即方式二的寫法,編譯時,會自動加上取值運算。而方式三的寫法可以直接賦值。

結構體標籤

struct 的每個字段上可以定義一個標籤(tag),該標籤可以通過反射機制獲取,最常見的使用場景就是序列化和反序列化。

type Person struct{
    Name string `json:"name"`
    Age int `json:"age"`
}

p := Person{"張三"30}
jsonStr, err := json.Marshal(p)
if err == nil {
    fmt.Println(string(jsonStr)) // {"name":"張三","age":30}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章