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 张三}}}
}