5、map&struct
阿新 • • 發佈:2018-11-13
1、map
map是雜湊表的引用,是一個無序的key/value對的集合,其中所有的key都是不同的,通過給定的key檢索、更新和刪除對應的value。map中所有的key都有相同的型別,所以的value也有著相同的型別,但是key和value之間可以是不同的資料型別。其中K對應的key必須是支援==比較運算子的資料型別,所以map可以通過測試key是否相等來判斷是否已經存在。
1.1 定義格式
var map_name map[key_type]value_type
//如果你錯誤的使用 new() 分配了一個引用物件,你會獲得一個空引用的指標,相當於聲明瞭一個未初始化的變數並且取了它的地址。
map_name :=make(map[key_type]value_type)
map_naem :=map[key_type]value_type{}
map_name := make(map[string]map[string]bool)/*Map的value型別也可以是一個聚合型別,比如是一個map或slice。
當我們要處理unix機器上的所有程序,以父程序(pid 為整形)作為 key,所有的子程序以所有子程序
的 pid 組成的切片)作為 value。通過將 value 定義為 []int 型別或者其他型別的切片,就可以優雅的解決這個問題。*/
1.2 初始化
/*map有初始容量,當 map 增長到容量上限的時候,如果再增加新的 key-value 對,map 的大小會自動加 1。
所以出於效能的考慮,對於大的 map 或者會快速擴張的 map,即使只是大概知道容量,也最好先標明。*/
map_name :=make(map[string]int,100)
map_name[key1]=value1
map_name=map[key_type]value_type{key1:value1 , key2:value2}
value1 :=map_name[key1]
1.3一般用法
myMap :=map[string] int{"雪":1}
fmt.Println(myMap["雪"])//1
delete(myMap,"雪")//內建的delete可以刪除元素,如果 key 不存在,該操作不會產生錯誤。
/*如果一個查詢失敗將返回value型別對應的零值,例如,即使map中不存在“bob”下面的程式碼也可以正常工作,
因為ages["bob"]失敗時將返回0。而且x += y和x++等簡短賦值語法也可以用在map上*/
myMap["雪"]+=1
/*map中的元素並不是一個變數,因此我們不能對map的元素進行取址操作,禁止對map元素取址的原
因是map可能隨著元素數量的增長而重新分配更大的記憶體空間,從而可能導致之前的地址無效。map是可以動態增長的。*/
a = &myMap["雪"]
/*遍歷map中全部的key/value對,Map的迭代順序是不確定的,並且不同的雜湊函式實現可能導致不同的遍歷順序。
在實踐中,遍歷的順序是隨機的,每一次遍歷的順序都不相同。這是故意的,每次都使用隨機的遍歷順序可以強制
要求程式不會依賴具體的雜湊函式實現。*/
for name,v :=range myMap{
fmt.Printf("%s\t%d\n",name,v)
}
/*在這種場景下,map的下標語法將產生兩個值;第二個是一個布林值,用於報告元素是否真的存在。
布林變數一般命名為ok,特別適合馬上用於if條件判斷部分。*/
if name, ok := myMap["雪"]; !ok { /* ... */ }
func equal(x,y map[string]int) bool {//判斷兩個map是否包含相同的key和value
if len(x) !=len(y){
return false
}
for xk,xv :=range x{
if yv,ok :=y[xk];!ok||yv!=xv{
return false
}
}
return true
}
/**/
1.4map型別的切片
package main
import "fmt"
func main() {//必須使用兩次 make() 函式,第一次分配切片,第二次分配 切片中每個
map 元素
// Version A:
items := make([]map[int]int, 5)
for i:= range items {
items[i] = make(map[int]int, 1)
items[i][1] = 2 }
fmt.Printf("Version A: Value of items: %v\n", items)
// Version B: NOT GOOD!
items2 := make([]map[int]int, 5)
for _, item := range items2 {
item = make(map[int]int, 1) // item is only a copy of the slice element.
item[1] = 2 // This 'item' will be lost on the next iteration.
}
fmt.Printf("Version B: Value of items: %v\n", items2)
}
1.5map排序
為 map 排序,需要將 key(或者 value)拷貝到一個切片,再對切片排序(使用 sort 包),然後可以使用切片的 for-range 方法打印出所有的 key 和 value。
// the telephone alphabet:
package main
import (
"fmt"
"sort"
)
var (
barVal = map[string]int{"alpha": 34, "bravo": 56, "charlie": 23,
"delta": 87, "echo": 56, "foxtrot": 12,
"golf": 34, "hotel": 16, "indio": 87,
"juliet": 65, "kili": 43, "lima": 98}
)
func main() {
fmt.Println("unsorted:")
for k, v := range barVal {
fmt.Printf("Key: %v, Value: %v / ", k, v)
}
keys := make([]string, len(barVal))
i := 0
for k, _ := range barVal {
keys[i] = k
i++
}
sort.Strings(keys)
fmt.Println()
fmt.Println("sorted:")
for _, k := range keys {
fmt.Printf("Key: %v, Value: %v / ", k, barVal[k])
}
}
2、struct結構體
結構體是一種聚合的資料型別,是由零個或多個任意型別的值聚合成的實體。
2.1 一般定義格式與初始化
//定義格式,如果結構體成員名字是以大寫字母開頭的,那麼該成員就是匯出的;這是Go語言匯出規則決定的。
type myStruct struct {a, b int}
type myStruct struct {
a type1
b,c type2
...
}
//初始化
myStruct1:={v1,v2,v3}
myStruct1:={a:v1,b:v2,c:v3}
//使用new,表示式 new(Type)和&Type{}是等價的。
var p *myStruct=new(myStruct)
p :=new(myStruct)
2.2基本操作
//訪問、賦值、對成員取地址
myStruct1.a//通過點訪問
myStruct1.a=2//賦值
p :=&myStruct1.a//取地址
*p=2+*p//指標訪問
var sp *struct =&myStruct1
sp.a=0//與下面相等
*sp.a=0
//一個命名為S的結構體型別將不能再包含S型別的成員:因為一個聚合的值不能包含它自身。(該限制同樣適應於陣列。)
//但是S型別的結構體可以包含*S指標型別的成員,這可以讓我們建立遞迴的資料結構,比如連結串列和樹結構等。
//使用一個二叉樹來實現一個插入排序
type tree struct {
value int
left, right *tree }
// Sort sorts values in place.
func Sort(values []int) {
var root *tree
for _, v := range values {
root = add(root, v) }
appendValues(values[:0], root) }
// appendValues appends the elements of t to values in order
// and returns the resulting slice.
func appendValues(values []int, t *tree) []int {
if t != nil {
values = appendValues(values, t.left)
values = append(values, t.value)
values = appendValues(values, t.right) }
return values
}
func add(t *tree, value int) *tree {
if t == nil {
// Equivalent to return &tree{value: value}.
t = new(tree)
t.value = value
return t }
if value < t.value {
t.left = add(t.left, value)
} else {
t.right = add(t.right, value)
}
return t
}
//結構體的比較:如果結構體的全部成員都是可以比較的,那麼結構體也是可以比較的,
//那樣的話兩個結構體將可以使用==或!=運算子進行比較。
2.3結構體嵌入和匿名成員
type point struct {
X, Y int }
type Circle struct {
Point
Radius int }
type Wheel struct {
Circle
Spokes int }
//對於匿名嵌入的特性,我們可以直接訪問葉子屬性而不需要給出完整的路徑,即是point是小寫(在包內部)
//但顯式形式訪問這些葉子成員的語法依然有效
var w Wheel
w.X = 8 // equivalent to w.Circle.point.X = 8
//結構體字面值並沒有簡短表示匿名成員的語
w = Wheel{8, 8, 5, 20}// compile error: unknown fields
w = Wheel{X: 8, Y: 8, Radius: 5, Spokes: 20} // compile error: unknown fields
//結構體字面值必須遵循形狀型別宣告時的結構
w = Wheel{Circle{Point{8, 8}, 5}, 20}
w = Wheel{
Circle: Circle{
Point: Point{X: 8, Y: 8}, Radius: 5,
},
Spokes: 20, // NOTE: trailing comma necessary here (and at Radius)
}
2.3結構體標籤
結構體中的欄位除了有名字和型別外,還可以有一個可選的標籤(tag):它是一個附屬於欄位的字串,可以是文件或其他的重要標記。標籤的內容不可以在一般的程式設計中使用,只有包 reflect 能獲取它。
package main
import (
"fmt"
"reflect"
)
type TagType struct { // tags
field1 bool "An important answer"
field2 string "The name of the thing"
field3 int "How much there are"
}
func main() {
tt := TagType{true, "Barak Obama", 1}
for i := 0; i < 3; i++ {
refTag(tt, i)
}
}
func refTag(tt TagType, ix int) {
ttType := reflect.TypeOf(tt)
ixField := ttType.Field(ix)
fmt.Printf("%v\n", ixField.Tag)
}