GO语言-07派生类型:map和结构体(上)

初心是记录和总结,自己学习Go语言的历程。如果能帮助到你,这是我的荣幸。

map

Map的概念在任何程序语言都一样,存储key-value这样的内容,通过key可以查到对应的valuekey是唯一的。

语法:
var map[key的类型]value的类型

例子:

//定义一个map,这时候没有初始化是不能直接使用的
var province map[string]string
province["ZheJiang"] = "浙江" //报错

未初始化的Map赋值会报错:panic: assignment to entry in nil map,说我们正在操作一个空的Map

panic指的是Go语言遇到一个异常时候强制执行让程序终止的操作

map初始化的几种方法

  • 使用make函数
  • 使用new定义一个指针,然后使用*解析地址赋给定义的map
  • 定义时同时赋值
//初始化方式一:使用make进行创建,初始指定容量为2
province = make(map[string]string, 2)
province["ZheJiang"] = "浙江"
province["ShangHai"] = "上海"
province["BeiJing"] = "北京"
// 初始化方式二:new返回的是一个指针
var province map[string]string
pointMap := new(map[string]string) // 返回的是一个map指针,指针是存地址的
province = *pointMap // *号的作用是解析地址
province["ZheJiang"] = "浙江"
province["ShangHai"] = "上海"
province["BeiJing"] = "北京"
// 我们手动给它初始化了,也是可以的
province := map[string]string{"JiangSu": "江苏", "SiChuan": "四川"}

查询map中是够包含某个键

基于map名[key名]的方式,会返回value和一个bool类型,通过bool可以判断是否含有这个键

_, ok := province["ZheJiang"] //_只是一个占位符
fmt.Println(ok)               //true

value, ok := province["ZheJiang"]
fmt.Println(value) //浙江
fmt.Println(ok) //true

遍历整个map

通过range的方式遍历Map,可以获得map的keyvalue。单独获取keyvalue,我们可以通过_我们可以舍去不需要的数据来实现,示例代码如下:

// 遍历Map
for key, value := range province {
   fmt.Println(key, value)
}

遍历Key

// 遍历Key
for key,_ := range province {
   fmt.Println(key)
}

遍历Value

// 遍历value
for _, value := range province {
   fmt.Println(value)
}

删除Map中的元素

使用内置函数delete,通过key删除map元素

delete(province, "ShangHai")

type关键字

使用type我们可以自定义类型。这很有必要,因为我们需要描述一件事的事情的时候是需要描述很多内容。就像人,这个人会有年龄,名字。我们需要把人的概念抽出来,然后就可以用人来形容世界上所有的人,因为我们将年龄,名字这种共性的东西抽出来,形成人的概念了。而go语言中并没有这个变量类型,只有int可以表示年龄,string可以表示名字。如何定义人这个类型呢?使用typestruct,先了解一下type

语法:

我们可以自定义类型,使用go语言提供type关键字,例如:

type myInt int

type是定义了一个全新的类型。我们可以基于内置的基本类型定义,上面的例子就是基于int定义的新类型myInt。现在我们准备回答这个类型怎么定义,通过type + struct

struct 结构体

结构体有点类似于Java定义的类,里面有成员变量和方法。恰恰,在Go语言中方法就是一个类型,所以这和Java的类很像!,这样有助于我们开始理解struct。拿个例子,定义一个person类型,它可以描述人的年龄和姓名。

语法:

type 类型名 struct {
    字段名 字段类型
    字段名 字段类型
    ...
} 

解读:type是用来表示自定义类型的,struct可以帮助我们使用多个字段类型来组成类型名这个类型,其实我们就是在定义一个复合类型,这个类型的名字最终交类型名

定义person类型:

type person struct{
    name string //描述姓名
    age int //描述年龄
}

定义完成之后,我们来定义一个person类型的变量取名为people,当输出people的时候,我们会发现该类型中包含的类型都被自动初始化了。

var people person
fmt.Println(people) //{ 0}

定义的变量我们可以通过.的方式访问到结构体中的字段名,并给与一些赋值的操作。

//通过类型.字段名的方式结构体的字段
people.name = "chengyunlai"
people.age = 18
fmt.Println(people) // {chengyunlai 18}

使用new的方式定义

我们使用new的方式定义的时候,我们知道其实返回的是一个指针,所以people2其实是一个person类型的指针,里面存放的是地址,当我们打印的时候可以发现前面是带了个&符号。

那我们当然知道*是解析地址的作用,在前面加了个*,发现打印出来就是实际的值

// 定义2 使用new返回指针的方式定义
people2 := new(person)
fmt.Println(people2)        //&{ 0}
fmt.Println(*(people2))     //{ 0}
fmt.Println((*people2).age) // 0

其实不用这么麻烦,Go语言为我们准备了语法糖,看代码

people2.age = 18 // 相当于(*people2).age = 18
fmt.Println(people2.age)

结构体里放方法?

学过java的人,又了解过go语言中方法其实是一个类型的时候,会很开心的想到在结构体里放方法,比如说设置一个setter方法,通过方法传参的方式设置nameage

type person struct {
   name    string //描述姓名
   age     int    //描述年龄
   setNameAndAge func(p *person, name string, age int)
}

这个需要用到指针的知识,小伙伴们可以自己尝试,我就不挖坑了,因为我试过了。指针传递过来的地址保证了我们操作的是同一个地址。

解读:
这里我们定义了一个方法setName func(p *person, name string, age int),方法名为setName,因为go没有this的用法,所以我们把对操作,写进了第一个变量中,我们需要做的是给nameint赋值,所以还定义了两个传入的参数。

使用:

var people person //定义person类型的变量为people

people.setNameAndAge = func(p *person, name_ string, age_ int) {
   p.name = name_
   p.age = age_
   fmt.Printf("%p\n", p) //0xc0000543c0
}

people.setNameAndAge(&people, "张三", 15)
fmt.Printf("%p\n", &people) //0xc0000543c0
fmt.Println(people) //{张三 15 0xa4fc80}

解读:
由于我尝试在结构体中写方法,但是失败了,失败的原因看语法就能明白,里面只能定义。所以只能实例化(var people person),像people.字段名的方法进行方法的赋值(确实感觉笨笨的~),当然我们可以考虑将方法抽出来这样将方法名赋值就行。后面我们会说一下go语言应对这种情况的解决办法。但是我这个思想还是挺重要的

people.setNameAndAge(&people, "张三", 15)传入了操作的地址,以及我想赋值的变量值,由于我的方法已经定义好了,在方法中我特地打印了一下地址,可以发现两个打印输出的地址是一样的,这就是指针的作用。

最后输出了fmt.Println(people) //{张三 15 0xa4fc80} 发现尝试成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值