go語言學習-語言容器

/*************************************************************************/

var 數組變量名 [元素數量]Type // 聲明數組

var a [3]int = [3]int{1, 2, 3}

q := [...]int{1, 2, 3} // 在數組長度的位置出現“...”省略號,則表示數組的長度是根據初始化值的個數來計算

p := [3]int{1, 2, 3}

p = [4]int{1, 2, 3, 4} // 編譯錯誤:無法將 [4]int 賦給 [3]int

a := [2]int{1, 2}

b := [...]int{1, 2}

c := [2]int{1, 3}

fmt.Println(a == b, a == c, b == c) // "true false false"

d := [3]int{1, 2}

fmt.Println(a == d) // 編譯錯誤:無法比較 [2]int == [3]int

var team [3]string // 遍歷訪問每一個元素

team[0] = "hammer"

team[1] = "soldier"

team[2] = "mum"

for k, v := range team {

fmt.Println(k, v)

}

/*************************************************************************/

/* --> 二、多維數組*/

// Go語言中允許使用多維數組,因為數組屬於值類型,所以多維數組的所有維度都會在創建時自動初始化零值,多維數組尤其適合管理具有父子關係或者與座標系相關聯的數據。


var array_name [size1][size2]...[sizen] array_type // 聲明多維數組

var array [4][2]int // 聲明一個二維整型數組,兩個維度的長度分別是 4 和 2

array = [4][2]int{{10, 11}, {20, 21}, {30, 31}, {40, 41}} // 使用數組字面量來聲明並初始化一個二維整型數組

array = [4][2]int{1: {20, 21}, 3: {40, 41}} // 聲明並初始化數組中索引為 1 和 3 的元素

array = [4][2]int{1: {0: 20}, 3: {1: 41}} // 聲明並初始化數組中指定的元素

var array1 [2][2]int = [2][2]int{{1,11}, {2,22}}

var array2 [2]int = array1[1] // 將array1中的索引為1的維度複製到一個同類型的數組 11,22

var array3 int = array1[1][0] // 將array1中指定整型值複製到新的整型變量中 1

/*************************************************************************/

/* --> 三、切片slice*/

// 切片默認指向一段連續內存區域,可以是數組,也可以是切片本身

slice [開始位置 : 結束位置] // 從連續內存區域生成切片,以位置索引計算

var a = [3]int{1, 2, 3}

fmt.Println(a, a[1:2]) // 輸出結果:[1 2 3] [2]

fmt.Println(a, a[:]) // 當開始和結束位置索引均為空時,生成的切片將和原切片在數據內容上一致

fmt.Println(a,a[0,0]) // 重置切片,結果為空列表

var strList []string // 聲明字符串切片

make( []Type, size, cap ) // 使用make()函數構造切片

// type是指切片元素類型。size指分配多少元素。cap指預分配的元素數,這個值設定不影響size,只是提前分配空間,降低多次分配造成的性能問題

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

/*************************************************************************/

/* --> 四、為切片添加元素*/

var a []int

a = append(a, 1) // 追加1個元素

a = append(a, 1, 2, 3) // 追加多個元素, 手寫解包方式

// 在使用 append() 函數為切片動態添加元素時,如果空間不足以容納足夠多的元素,切片就會進行“擴容”,此時新切片的長度會發生改變

var a = []int{1,2,3}

a = append([]int{0}, a...) // 在開頭添加1個元素

a = append([]int{-3,-2,-1}, a...) // 在開頭添加1個切片

// 在切片開頭添加元素一般都會導致內存的重新分配,而且會導致已有元素全部被複制 1 次,因此,從切片的開頭添加元素的性能要比從尾部追加元素的性能差很多

var a []int

a = append(a[:i], append([]int{x}, a[i:]...)...) // 在第i個位置插入x

a = append(a[:i], append([]int{1,2,3}, a[i:]...)...) // 在第i個位置插入切片

/*************************************************************************/

/* --> 五、切片複製*/

copy( destSlice, srcSlice []T) int

slice1 := []int{1, 2, 3, 4, 5}

slice2 := []int{5, 4, 3}

copy(slice2, slice1) // 只會複製slice1的前3個元素到slice2中

copy(slice1, slice2) // 只會複製slice2的3個元素到slice1的前3個位置

/*************************************************************************/

/* --> 六、從切片中刪除元素*/

/*

Go語言並沒有對刪除切片元素提供專用的語法或者接口,需要使用切片本身的特性來刪除元素,根據要刪除元素的位置有三種情況,

分別是從開頭位置刪除、從中間位置刪除和從尾部刪除,其中刪除切片尾部的元素速度最快。

*/

a = []int{1, 2, 3}

a = a[1:] // 刪除開頭1個元素

a = a[N:] // 刪除開頭N個元素

a = []int{1, 2, 3}

a = append(a[:0], a[1:]...) // 刪除開頭1個元素

a = append(a[:0], a[N:]...) // 刪除開頭N個元素

a = []int{1, 2, 3}

a = a[:copy(a, a[1:])] // 刪除開頭1個元素

a = a[:copy(a, a[N:])] // 刪除開頭N個元素

// Go語言中刪除切片元素的本質是,以被刪除元素為分界點,將前後兩個部分的內存重新連接起來

func main() {

seq := []string{"a", "b", "c", "d", "e"}

// 指定刪除位置

index := 2

// 查看刪除位置之前的元素和之後的元素

fmt.Println(seq[:index], seq[index+1:]) // [a b] [d e]

// 將刪除點前後的元素連接起來

seq = append(seq[:index], seq[index+1:]...)

fmt.Println(seq) // [a b d e]

}

/*************************************************************************/

/* --> 七、range,循環迭代切片*/

// 創建一個整型切片,並賦值

slice := []int{10, 20, 30, 40}

// 迭代每一個元素,並顯示其值

for index, value := range slice {

fmt.Printf("Index: %d Value: %d\\n", index, value)

}

// range 返回的是每個元素的副本,而不是直接返回對該元素的引用

// 創建一個整型切片,並賦值

slice := []int{10, 20, 30, 40}

// 迭代每個元素,並顯示值和地址

for index, value := range slice {

fmt.Printf("Value: %d Value-Addr: %X ElemAddr: %X\\n", value, &value, &slice[index])

}

/*

Value: 10 Value-Addr: 10500168 ElemAddr: 1052E100

Value: 20 Value-Addr: 10500168 ElemAddr: 1052E104

Value: 30 Value-Addr: 10500168 ElemAddr: 1052E108

Value: 40 Value-Addr: 10500168 ElemAddr: 1052E10C

*/

/*************************************************************************/

/* --> 八、多維切片*/

slice := [][]int{{10}, {100, 200}}

// 為第一個切片追加值為 20 的元素

slice[0] = append(slice[0], 20)

/*************************************************************************/

/* --> 九、map 映射*/

// 類似於字典

// 和數組不同,map 可以根據新增的 key-value 動態的伸縮

var mapname map[keytype]valuetype // 聲明方式,keytype指鍵的類型,valuetype指鍵對應值的類型

func main() {

var mapLit map[string]int

//var mapCreated map[string]float32

var mapAssigned map[string]int // 聲明

mapLit = map[string]int{"one": 1, "two": 2} // 初始化

mapCreated := make(map[string]float32) // 初始化

mapAssigned = mapLit

mapCreated["key1"] = 4.5

mapCreated["key2"] = 3.14159

mapAssigned["two"] = 3

fmt.Printf("Map literal at \"one\" is: %d\\n", mapLit["one"])

fmt.Printf("Map created at \"key2\" is: %f\\n", mapCreated["key2"])

fmt.Printf("Map assigned at \"two\" is: %d\\n", mapLit["two"])

fmt.Printf("Map literal at \"ten\" is: %d\\n", mapLit["ten"])

}

/*

1、mapCreated 的創建方式mapCreated := make(map[string]float)等價於mapCreated := map[string]float{}

2、mapAssigned 是 mapList 的引用,對 mapAssigned 的修改也會影響到 mapLit 的值

3、可以使用 make(),但不能使用 new() 來構造 map,如果錯誤的使用 new() 分配了一個引用對象,

會獲得一個空引用的指針,相當於聲明瞭一個未初始化的變量並且取了它的地址:mapCreated := new(map[string]float)

4、

*/

// 遍歷同樣使用range或者for循環

// 使用delete()函數從map中刪除鍵值對

delete(map, 鍵)

// 清空map中的所有元素,GO語言中沒有為map提供任何清空的函數,唯一的辦法就是重新make一個新的map

/*************************************************************************/

/* --> 十、sync.Map 在併發環境中使用的map*/

// Go語言中的 map 在併發情況下,只讀是線程安全的,同時讀寫是線程不安全的

// sync.Map相對於map性能有所損失,所以,在非併發的情況下使用map比較好

// 如果在非併發的情況下使用map的同時使用鎖,性能則不如sync.Map

sync.Map // 和map不同,sync.Map是sync包下的特殊結構

/*

sync.Map有以下幾點特性

2、sync.Map不能使用map的方式進行取值和設置等操作,俄日是使用sync.Map的方法進行調用

Store表示存儲,Load表示獲取。Delete表示刪除

3、使用Range配合一個回調函數進行遍歷操作,通過回調函數返回內部遍歷出來的值,

Range參數中回調函數的返回值在需要繼續迭代遍歷時,返回true,終止迭代遍歷時,返回false

*/

func main() {

var scene sync.Map

// 將鍵值對保存到sync.Map

scene.Store("greece", 97)

scene.Store("london", 100)

scene.Store("egypt", 200)

// 從sync.Map中根據鍵取值

fmt.Println(scene.Load("london")) // 100 true

// 根據鍵刪除對應的鍵值對

scene.Delete("london")

// 遍歷所有sync.Map中的鍵值對

scene.Range(func(k, v interface{}) bool {

fmt.Println("iterate:", k, v) // iterate: egypt 200 iterate: greece 97

return true

})

}

/*

Range方法可以遍歷sync.Map,但遍歷需要提供一個匿名函數,參數為 k、v,類型為 interface{},

每次 Range() 在遍歷一個元素時,都會調用這個匿名函數把結果返回。

Range 參數中回調函數的返回值在需要繼續迭代遍歷時,返回 true,終止迭代遍歷時,返回 false

*/

/*************************************************************************/

/* --> 十一、列表*/

/*

1、列表初始化,分別可以使用New()函數和var關鍵字,兩者效果一致

2、列表與切片和map不同的是,列表沒有具體元素類型的限制。風險:放入一個interface{}類型的值,

取出後如果將interface{}轉換為其他類型將會發生宕機

3、go語言中的列表為雙鏈表類型的,支持從隊列前後插入元素,PushFront和PushBack

4、上面兩個方法都會返回一個*list.Element結構,如果需要刪除之前插入的元素,則只能通過

*list.Element配合Remove()方法刪除

*/

l := list.New() // 初始化一個空列表

l.PushBack("fist") // 將字符串插入列表尾部

l.PushFront(67) // 將字符串插入列表頭部

func main() {

l := list.New()


l.PushBack("canon") // 尾部添加


l.PushFront(67) // 頭部添加


element := l.PushBack("fist") // 尾部添加後保存元素句柄


l.InsertAfter("high", element) // 在fist之後添加high


l.InsertBefore("noon", element) // 在fist之前添加noon


l.Remove(element) // 移除element對應的元素

}

// 遍歷列表

l := list.New()

l.PushBack("canon") // 尾部添加

l.PushFront(67) // 頭部添加

for i := l.Front(); i != nil; i = i.Next() {

fmt.Println(i.Value)

}

/*

使用 for 語句進行遍歷,其中 i:=l.Front() 表示初始賦值,只會在一開始執行一次,

每次循環會進行一次 i != nil 語句判斷,如果返回 false,表示退出循環,反之則會執行 i = i.Next()

*/

/*************************************************************************/

/* --> 十二、make和new關鍵字的區別及實現原理*/

// new 函數,它返回的永遠是類型的指針,指針指向分配類型的內存地址

// 內置類型數據分配內存

var sum *int

sum = new(int) //分配空間

*sum = 98

fmt.Println(*sum)

// 自定義類型new

type Student struct {

name string

age int

}

var s *Student // 聲明一個指針s

s = new(Student) //分配空間

s.name ="dequan"

// make只用於 chan、map 以及 slice 的內存創建,而且它返回的類型就是這三個類型本身,而不是他們的指針類型


分享到:


相關文章: