GO語言中map和struct是兩個非常常用的資料類型,這裡單獨來學習
1、map
GO語言中map的結構是map[k]v,map中所有的k類型必須相同,所有v的類型也必須相同,但是k和v的類型沒有要求必須相同,看下面一段代碼,我們使用三種方法來建立一個map:
arr := make(map[string]int) //第一種使用make
arr:=map[string]int{"a":1, "b":2, "c":3} //第二種方法,這種方法建立map必須進行初始化
arr := map[string]int{} //第三種方法建立一個空的map,這個其實是第二種的一個特性形式
以上三種建立方法,一般來說建議使用make函數進行建立。
通路時使用下标進行通路arr["a"],那麼取到的值為1
使用make函數建立的map我們初始化時可以采用下面的方式進行:
arr := make(map[string]int) //第一種使用make
arr["a"] = 1
arr["b"] = 2
fmt.Println(arr)
使用for循環來周遊map,看下面一段代碼:
arr := make(map[string]int) //第一種使用make
arr["a"] = 1
arr["b"] = 2
arr["c"] = 3
//取key和value一起
for k, v := range arr {
fmt.Println(k, v)
}
//隻取value
for _, v := range arr {
fmt.Println(v)
}
//隻取key
for k, _ := range arr {
fmt.Println(k)
}
删除一個元素使用内置函數delete, delete函數的參數為delete(map, key),map為要操作的map,key為要删除元素的key值:
arr := make(map[string]int) //第一種使用make
arr["a"] = 1
arr["b"] = 2
arr["c"] = 3
fmt.Println(arr)
delete(arr, "b")
fmt.Println(arr)
對map進行操作的時候,需要注意的一點是,零值map是不能進行指派的,不然出錯,map的零值是nil,如果需要對零值map進行指派的話,需要先對map進行初始化,下面用一段代碼來進行說明:
var arr map[string]int
fmt.Println(arr == nil, len(arr), arr) //true, 0 //0
//arr["a"] = 1 //出錯,這裡對零值map進行指派
arr = make(map[string]int) //初始化arr
arr["a"] = 1
fmt.Println(arr == nil, len(arr), arr)
需要從map中進行取值得時候,不管key值是什麼總會有值,如上例中,如果取arr["x"],那麼取到的結果是0,那麼怎麼樣來進行判斷map中是否存在這樣的key值呢,我們用下面一段代碼來進行說明:
arr := map[string]int{"a": 1, "b": 2, "c": 3} //初始化map
v := arr["x"] //取下标為x的值
fmt.Println(v) //0,這裡取到了值,那麼我們就無法判斷這個下标是否存在
_, ok := arr["x"]
fmt.Println(ok) //0, false
if ok { //用這種方式來進行判斷
//我們自己的操作
}
if _, ok := arr["x"]; ok { //上面的也可以寫成這樣一行
//我們自己的操作
}
使用map下标進行取值的時候,會傳回兩個參數,第一個參數是下标對應的值,第二個參數是一個布爾型的值,如果這個下标不存在在map中那麼傳回false,存在傳回true。這樣我們就很容易的判斷出map中是否存在下标對應的值。
2、struct結構體
結構體是将0個或者多個任意資料類型的變量組成的資料集合,下面我們用一段代碼來看看結構體的定義,指派和使用:
// stydy project main.go
package main
import (
"fmt"
)
type person struct {
name string //姓名
age int //年齡
address string //住址
ID string //身份證号
}
func compare(p1 person, p2 person) person {
if p1.age >= p2.age {
return p1
} else {
return p2
}
}
func main() {
p := new(person) //
p.name = "張三"
p.age = 15
p.address = "陝西西安"
p.ID = "123456789445555"
fmt.Println(*p)
var p1, p2 person
p1.name, p2.name = "p1", "p2"
p1.age, p2.age = 15, 17
pp := compare(p1, p2)
fmt.Println(pp)
}
執行結果:
在GO語言中定義的變量的跨包可通路性是用首字母的大小寫來進行判斷的,這裡需要說明的是,結構體也是一樣,結構體的聲明,如上,如果person首字母小寫,那麼其它包是不能使用的。結構體中的變量定義同樣如此,如果結構體重的變量首字母大寫,那麼跨包可以通路,如果小寫是不可以的。
當一段程式中需要使用多個結構體,且這些結構體之間有關聯關系時,比如學校(shcool),班級(class),學生(student),他們之間是有關系的,那麼我們怎麼來操作呢,這個時候就需要用代碼來直覺的說明:
package main
import (
"fmt"
)
type Student struct {
SNO uint //學号
SName string //姓名
}
type Class struct {
CNO uint //班級編号
CName string //班級名稱
CStudent Student //學生
}
type School struct {
ScNO uint //學校編号
ScName string //學校名稱
SClass Class //班級
}
func main() {
var sc School
sc.ScNO = 1
sc.ScName = "西安交大"
sc.SClass.CName = "一班"
sc.SClass.CStudent.SName = "張三"
fmt.Println(sc)
}
從上面可以看出,當我們給班級和學生指派的時候感覺很煩,需要引用的太長,那麼有沒有一種更加簡便的方法呢,答案是有的。struct為我們提供了一種允許定義一個不帶名稱的成員,這個隻需要定義類型即可;這種結構體成員成為匿名成員。下面我們在來看一下簡化後的代碼:
// stydy project main.go
package main
import (
"fmt"
)
type Student struct {
SNO uint //學号
SName string //姓名
}
type Class struct {
CNO uint //班級編号
CName string //班級名稱
Student //學生
}
type School struct {
ScNO uint //學校編号
ScName string //學校名稱
Class //班級
}
func main() {
var sc School
sc.ScNO = 1
sc.ScName = "西安交大"
sc.CName = "一班"
sc.SName = "張三"
fmt.Println(sc)
}
這樣寫是不是舒服了很多呢。
最後在提供兩種直接初始化struct的方法:
// stydy project main.go
package main
import (
"fmt"
)
type Student struct {
SNO uint //學号
SName string //姓名
}
type Class struct {
CNO uint //班級編号
CName string //班級名稱
Student //學生
}
type School struct {
ScNO uint //學校編号
ScName string //學校名稱
Class //班級
}
func main() {
sc := School{1, "西安交大", Class{2, "一班", Student{3, "張三"}}}
fmt.Println(sc) //{1 西安交大 {2 一班 {3 張三}}}
sc = School{
ScNO: 1,
ScName: "西安交大",
Class: Class{
CNO: 2,
CName: "一班",
Student: Student{
SNO: 3,
SName: "張三",
},
},
}
fmt.Println(sc) //{1 西安交大 {2 一班 {3 張三}}}
}