map

map是key-value数据结构,又称为字段或者关联数组,雷士其他编程语言的集合,在编程中经常使用到。

语法

var map变量名 map[keytype]valuetype

golang中的map,的key可以是很多种类型,比如bool,数字,string,指针,channel,还可以是只包含前面几个类型的接口、结构体、数组。通常为int,string

valuetype的类型和key基本一样,通常为数字(整数、浮点数),string,map,struct

map声明

声明是不会分配内存的,初始化需要make,分配内存后才能赋值和使用

package mainimport "fmt"func main() {// map的声明,注意事项var a map[string]string// 空map不能直接赋值// 在使用map前,需要先make,make的作用就是给map分配数据空间a = make(map[string]string, 10)a["num1"] = "宋江"a["num2"] = "吴用"fmt.Println(a)// key不能重复a["num1"] = "武松"fmt.Println(a)// value可以从夫a["num3"] = "吴用"fmt.Println(a)
}
  1. map在使用前一定要make

  1. map的key是不能重复,如果重复了,则以最后这个key-value为准

  1. map的value是可以相同的

  1. map的key-value是无序的

  1. make内置函数

使用方式

// 方式一
var a map[string]string
// 空map不能直接赋值
// 在使用map前,需要先make,make的作用就是给map分配数据空间
a = make(map[string]string, 10)
a["num1"] = "宋江"
a["num2"] = "吴用"
fmt.Println(a)
// 方式2
cities := make(map[string]string)
cities["no1"] = "北京"
cities["no2"] = "天津"
cities["no3"] = "上海"
fmt.Println(cities)
// 第三种方式
heros := map[string]string{"hero1": "宋江","hero2": "卢俊义",
}
fmt.Println("heroes=", heros)

案例

package mainimport "fmt"func main() {// // map的声明,注意事项// var a map[string]string// // 空map不能直接赋值// // 在使用map前,需要先make,make的作用就是给map分配数据空间// a = make(map[string]string, 10)// a["num1"] = "宋江"// a["num2"] = "吴用"// fmt.Println(a)// // key不能重复// a["num1"] = "武松"// fmt.Println(a)// // value可以从夫// a["num3"] = "吴用"// fmt.Println(a)// 方式一var a map[string]string// 空map不能直接赋值// 在使用map前,需要先make,make的作用就是给map分配数据空间a = make(map[string]string, 10)a["num1"] = "宋江"a["num2"] = "吴用"fmt.Println(a)// 方式2cities := make(map[string]string)cities["no1"] = "北京"cities["no2"] = "天津"cities["no3"] = "上海"fmt.Println(cities)// 第三种方式heros := map[string]string{"hero1": "宋江","hero2": "卢俊义",}fmt.Println("heroes=", heros)studentMap := make(map[string]map[string]string)studentMap["stu01"] = make(map[string]string, 3)studentMap["stu01"]["name"] = "tom"studentMap["stu01"]["sex"] = "男"studentMap["stu01"]["address"] = "北京长安街~"studentMap["stu02"] = make(map[string]string, 3)studentMap["stu02"]["name"] = "mary"studentMap["stu02"]["sex"] = "女"studentMap["stu02"]["address"] = "上海黄浦街~"fmt.Println(studentMap)fmt.Println(studentMap["stu01"])fmt.Println(studentMap["stu01"]["address"])
}

map增删改查

  1. 因为key已经存在,重新赋值相当于修改

cities := make(map[string]string)
cities["no1"] = "北京"
cities["no2"] = "天津"
cities["no3"] = "上海"
fmt.Println(cities)// 因为key已经存在,重新赋值相当于修改
cities["no3"] = "深圳"
fmt.Println(cities)
  1. 内置函数delet(),delete(map,key),当delet指定的key不存在时,删除不会操作,也不会报错

// 因为key已经存在,重新赋值相当于修改
cities["no3"] = "深圳"
fmt.Println(cities)
  1. 如果我们要删除map的所有key,没有一个专门的方法一次删除,可以遍历一下key,逐个删除

  1. 或者map = make(...),make一个新的,让原来的成为垃圾,被gc回收

  1. map查找

val, ok := cities["no2"]
if ok {fmt.Printf("有 no2 key 值为%v\n", val)
} else {fmt.Printf("没有no2 key\n")
}

map遍历

for k, v := range cities {fmt.Printf("k=%v,v=%v\n", k, v)
}
studentMap := make(map[string]map[string]string)studentMap["stu01"] = make(map[string]string, 3)
studentMap["stu01"]["name"] = "tom"
studentMap["stu01"]["sex"] = "男"
studentMap["stu01"]["address"] = "北京长安街~"studentMap["stu02"] = make(map[string]string, 3)
studentMap["stu02"]["name"] = "mary"
studentMap["stu02"]["sex"] = "女"
studentMap["stu02"]["address"] = "上海黄浦街~"for k1, v1 := range studentMap {fmt.Println(k1 + ":")for k2, v2 := range v1 {fmt.Printf("\t %v = %v v2=%v\n", k1, k2, v2)}fmt.Println()
}

map的长度

len(map)

map切片

切片的数据类型如果是map,我们称slice of map,map切片,这样使用则map的个数可以动态变化

package mainimport "fmt"func main() {var monsters []map[string]stringmonsters = make([]map[string]string, 2)if monsters[0] == nil {monsters[0] = make(map[string]string, 2)monsters[0]["name"] = "牛魔王"monsters[0]["age"] = "500"}if monsters[1] == nil {monsters[1] = make(map[string]string, 2)monsters[1]["name"] = "玉兔精"monsters[1]["age"] = "400"}fmt.Println(monsters)//使用切片的append函数,可以动态的增加monstrnewMoster := map[string]string{"name": "天魔","age":  "200",}monsters = append(monsters, newMoster)fmt.Println(monsters)
}

map排序

  1. golang中没有一个专门的方法针对map的key进行排序

  1. golang中的map默认是升序的,注意也不是按照顺序存放的,每次遍历,得到的输出可能不一样

  1. golang中的map的排序,事先将key进行排序,然后根据key值遍历输出

使用细节

  1. map是引用类型,遵守引用类型的传递机制,在一个函数接收map,修改后,会直接修改原来的map

package mainimport "fmt"func modify(map1 map[int]int) {map1[10] = 900
}func main() {map1 := make(map[int]int)map1[1] = 90map1[2] = 88map1[10] = 12map1[12] = 3modify(map1)// 说明map是引用类型fmt.Println(map1)
}
  1. map的容量达到后,在想map增加元素,会自动扩容,并不会发生panic,也就是说map能动态的增长键值对(key-value)

  1. map的value也经常使用struct类型,更适合管理复杂的数据,比如value可以为Student结构体

package mainimport ("fmt"
)func modify(map1 map[int]int) {map1[10] = 900
}type stu struct {Name    stringAge     intAddress string
}func main() {map1 := make(map[int]int)map1[1] = 90map1[2] = 88map1[10] = 12map1[12] = 3modify(map1)// 说明map是引用类型fmt.Println(map1)students := make(map[string]stu, 10)stu1 := stu{"Tom", 18, "北京"}stu2 := stu{"Marry", 18, "上海"}students["no1"] = stu1students["no2"] = stu2fmt.Println(students)
}

面向"对象"编程

  1. Golang支持面向对象编程(OOP),但是和传统的面向对象变成有区别,并不是纯粹的面向对象语言,

  1. Golang没有类(class),Go语言的结构体(struct)和其他编程语言的类(class)有同等的地位,可以理解为Golang是基于struct来实现OOP特性的

  1. Golang面向对象编程非常简洁,去掉了传统的OOP语言的继承、方法重载、构造函数和析构函数、隐藏的this指针等等

  1. Golang仍然有面向对象编程的继承,封装和多态的特性,只是实现的方式和其他OOP语言不一样,比如继承:Golang没有extends关键字,继承是通过匿名函数名字段来实现的

  1. Golang面向对象(OOP)很优雅,OOP本身就是语言类型系统(type system)的一部分,通过过接口(interface)关联,耦合性低,也非常灵活,在Golang中面向接口编程是非常重要的特性

结构体

  1. 将一类事物的特征提取出来,形成一个新的数据类型,就是一个结构体

  1. 通过这个个结构体,我们可以创建多个变量

案例

package mainimport "fmt"type Cat struct {Name  stringAge   intColor string
}func main() {var cat1 Catcat1.Name = "tom"cat1.Age = 12cat1.Color = "blue"fmt.Println(cat1)
}

结构体与结构体变量(实例)的区别和联系

  1. 结构体是自定义的数据类型,代表一类事物

  1. 结构体变量(实例)是具体的,实际的,代表一个具体变量

字段/属性

  1. 从概念或叫法上看,结构体的字段=属性=field

  1. 字段是结构体的一个组成部分,一般基本数据类型、数组,也可是引用类型

注意事项

  1. 字段声明语法同变量,字段名 字段类型

  1. 字段的类型可以为:基本类型、数组或引用类型

  1. 在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值

package mainimport "fmt"type Person struct {Name   stringAge    intScores [5]float64ptr    *intslice  []intmap1   map[string]string
}func main() {var p1 Personfmt.Println(p1)if p1.ptr == nil {fmt.Println("ok1")}if p1.slice == nil {fmt.Println("ok2")}if p1.map1 == nil {fmt.Println("ok3")}p1.slice = make([]int, 1)p1.slice[0] = 100fmt.Println(p1)
}
  1. 不同结构体变量的字段是独立的,互不影响,一个结构体变量字段的更改,不影响另外一个。

创建结构体变量和访问结构体字段

  1. 方式一

var p1 Person
fmt.Print(p1)
  1. 方式二

var p1 Person
fmt.Print(p1)
  1. 方式三

//方式三
var p3 *Person = new(Person)
(*p3).Name = "smith"
(*p3).Age = 30
// go的设计者,为了程序员使用方柏霓,底层会对p3.Name进行处理
p3.Name = "li"
fmt.Println(p3)
  1. 方法四

var p4 *Person = &Person{}
fmt.Println(p4)

结构体的注意事项

  1. 结构体的所有字段在内存中是连续的

package mainimport "fmt"type Point struct {x inty int
}type Rect struct {leftUp, rightDown Point
}type Rect2 struct {leftUp, rightDown *Point
}func main() {r1 := Rect{Point{1, 2}, Point{3, 4}}fmt.Printf("r1.leftUp.x 地址为%p\n", &r1.leftUp.x)fmt.Printf("r1.leftUp.y 地址为%p\n", &r1.leftUp.y)fmt.Printf("r1.rightDown.x 地址为%p\n", &r1.rightDown.x)fmt.Printf("r1.rightDown.y 地址为%p\n", &r1.rightDown.y)// r2有两个 *Point雷诺高兴,这两个*Point类型本身地址也是连续的// 但他们指向的地址不一定是连续的r2 := Rect2{&Point{10, 20}, &Point{30, 40}}fmt.Printf("r2.leftUp 地址为%p\n", &r2.leftUp)fmt.Printf("r2.rightDown 地址为%p\n", &r2.rightDown)fmt.Printf("r2.leftUp.x 地址为%p\n", &r2.leftUp.x)fmt.Printf("r2.leftUp.y 地址为%p\n", &r2.leftUp.y)fmt.Printf("r2.rightDown.x 地址为%p\n", &r2.rightDown.x)fmt.Printf("r2.rightDown.y 地址为%p\n", &r2.rightDown.y)
}
  1. 结构体是用户单独定义的类型,和其他类型进行转换时需要有完全相同的字段(名字、个数和类型)

package mainimport "fmt"type A struct {Num int
}
type B struct {Num int
}func main() {var a Avar b Ba = A(b)fmt.Println(a,b)
}
  1. 结构体进行type重新定义(想当与取别名),Golang认为是新的数据类型,但是相互间可以强转

package mainimport "fmt"type Student struct {Name stringAge  int
}type Stu Studenttype integer intfunc main() {var stu1 Studentvar stu2 Stustu2 = Stu(stu1)fmt.Println(stu1, stu2)var i integer = 10var j int = 20j = int(i)fmt.Println(i, j)
}
  1. struct的每个字段山,可以写一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列号和反序列化

将struct变量进行json处理

package mainimport ("encoding/json""fmt"
)type Monster struct {Name  string `json:"name"`Age   int    `json:"age"`Skill string `json:"skill"`
}func main() {monster := Monster{"牛魔王", 500, "芭蕉扇"}// json.Marshal函数中使用了反射jsonMonster, err := json.Marshal(monster)if err != nil {fmt.Println("json 处理错误", err)}fmt.Println("jsonMonster", string(jsonMonster))
}

方法

在某些情况下,我们需要声明(定义)方法。

Golang中的方法是作用在指定数据类型上的,因此自定义类型,都可以有方法,而不是struct

type A struct{

Num int

}

func (a A)test(){

fmt.Println(a.Num)

}

  1. func (a A)test(){}表示A结构体有一方法,方法名test

  1. (a A)体现test方法是和A类型绑定的

package mainimport "fmt"type Person struct {Name string
}func (p Person) test() {fmt.Println("test()", p.Name)
}func main() {var p Personp.Name = "tom"p.test()
}

快速入门

func main() {var p Personp.Name = "tom"p.speak()p.jisuan()p.jisuan2(100)res := p.getsum(10, 20)fmt.Println("res=", res)
}
  1. 给Person结构体添加speak方法,输出XX是一个b( ̄▽ ̄)d 

func (p Person) speak() {fmt.Println(p.Name, "是一个goodman")
}
  1. 给Person结构体添加jisaun方法,可以计算1+...+1000的结果

func (p Person) jisuan() {res := 0for i := 1; i < 1000; i++ {res += i}fmt.Println(p.Name, "计算的结果=", res)
}
  1. 给Person结构体jisuan2方法,该方法可以接受一个数n,计算1+...+n的结果

func (p Person) jisuan() {res := 0for i := 1; i < 1000; i++ {res += i}fmt.Println(p.Name, "计算的结果=", res)
}func (p Person) jisuan2(n int) {res := 0for i := 1; i < n; i++ {res += i}fmt.Println(p.Name, "计算的结果=", res)
}
  1. 给Person结构体添加getSum方法,可以计算两个数的和,并返回结果

func (p Person) getsum(n1 int, n2 int) int {return n1 + n2
}

方法的调用和传参机制原理

方法的调用和传参机制和函数基本一样,不一样的地方是方法调用时,会将调用方法的变量,当作实参传递给方法

  1. 在通过一个变量去调用方法时,其调用机制和函数一样

  1. 不一样的地方时,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地址拷贝)

案例

package mainimport "fmt"type Cricle struct {radius float64
}func (c Cricle) area() float64 {return 3.14 * c.radius * c.radius
}func main() {var c Criclec.radius = 4.0res := c.area()fmt.Println("面积是=",res)
}

方法的声明(定义)

func (recrvier type) methodName(参数列表)(返回值列表){

方法体

return 返回值

}

  1. 参数列表:表示方法的输入

  1. recever type:表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型

  1. receiver type:type可以是结构体,也可以是其他自定义类型

  1. receiver:就是type类型的一个变量,比如:Person结构体的一个变量

  1. 参数列表:表示方法的输入

  1. 返回值列表:表示返回的值,可以有多个

  1. 方法的主体,表示为了实现某一功能代码块

  1. return 语句不是必须的

方法的注意事项和细节讨论

  1. 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式

  1. 如程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理

  1. Golang中的方法是作用在指定的数据类型上的,和数据类型绑定,因此自定义类型,都可以有方法,而不仅仅是struct,比如int,float32等都可以有方法

  1. 方法的访问范围控制的规则,和函数一样,方法名首字母小写,只能在本包访问,方法首字母大写,可以在本包和其他包访问

  1. 如果一个变量实现了String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出

方法和函数的区别

  1. 调用方式不一样

  1. 函数调用方式: 函数名(实参列表)

  1. 方法的调用方式: 变量.方法名(实参列表)

  1. 对于普通函数,接收者为值类型是,不能将指针类型的数据直接传递,反之亦然

  1. 对于方法(如struct的方法),接收者为值类型时,可以直接使用指针类型的变量调用方法,反过来同样可以。

package mainimport "fmt"type Person struct {Name string
}func test01(p Person) {fmt.Println(p.Name)
}func test02(p *Person) {fmt.Println(p.Name)
}func (p Person) test03() {fmt.Println("test03() =", p.Name)
}func main() {p := Person{"tom"}test01(p)test02(&p)p.test03()// 值拷贝,从形式上看是传入地址,但本质上仍是值拷贝(&p).test03()
}

Golang学习 Day_09相关推荐

  1. Golang学习-基础命令

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. . Golang学习-基础命令 一.go run 用于运行命令源码文件,只能接收一个命令源码文件以及若干个库源码文件作为 ...

  2. golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题

    golang学习笔记12 beego table name `xxx` repeat register, must be unique 错误问题 今天测试了重新建一个项目生成新的表,然后复制到旧的项目 ...

  3. Golang学习(10)——bufio包

    Golang学习 - bufio 包 ------------------------------------------------------------ // bufio 包实现了带缓存的 I/ ...

  4. Golang学习(12)——regex包

    Golang学习 - regexp 包 ------------------------ // 函数 // 判断在 b(s.r)中能否找到 pattern 所匹配的字符串 func Match(pat ...

  5. Duang~ Golang 学习初探

    Duang~  Golang学习初步体验,一直以来都对Go语言有一定的喜感,今天花了点时间初步的了解了下Go,其实很多东西弄个小例子go run下会明白很多东西的. 本人开发工具使用的是GoSubli ...

  6. golang学习笔记(五):数组的定义和使用

    golang 学习笔记 数组定义 数组是一系列相同数据类型在内存中有序存储的数据集合 var 数组名 [元素个数]数据类型//定义了10个整型变量的数组元素var arr [10]int//通过下标找 ...

  7. golang 学习 - chan以及chan的一下用例

    golang 学习 - chan 1. 通道 // _通道_ 是连接多个 Go 协程的管道.你可以从一个 Go 协程 // 将值发送到通道,然后在别的 Go 协程中接收.package mainimp ...

  8. golang学习之negroni/gizp源码分析

    在 Go 语言里,Negroni 是一个很地道的 Web 中间件,它是一个具备微型.非嵌入式.鼓励使用原生 net/http 库特征的中间件.利用它地Use功能,我们可以很简单地自定义中间件并使用.其 ...

  9. 一顿烤羊腿换来的Golang学习路线

    作者:阿秀 阿秀的求职笔记:https://interviewguide.cn 你好,我是阿秀. 这篇学习路线写完其实很久了,不过前段时间又请组内的Go后端资深研发工程师吃了一顿烤羊腿. 向他请教了一 ...

最新文章

  1. php点击按钮加载控制器,php – Codeigniter 3自动加载控制器
  2. 栅极电阻要取100欧姆?
  3. Windows 10 Creators Update 4 月 11 日开始推送
  4. REST framework 基本使用
  5. 遇到问题:push的时候出现fatal: Authentication failed for
  6. ITK:灰度图像中的聚类像素
  7. xmanager 使用
  8. u3d 总是背向相机_纪念光学科学家“肖特”的相机
  9. python choose语句作用_理解闭包是如何与变量作用域相互影响的
  10. php 打印 wap,PHP 输出简单动态WAP页面
  11. Hive DDL DML
  12. 2018北京ICPC D. Frog and Portal(构造)
  13. 一款盲盒的交友软件叫什么(微信恋爱脱单交友盲盒小程序制作开发介绍)
  14. 搭档之家:哭唧唧!暗地较劲得不偿失,美团暂停支付宝后被无情反超
  15. colsure php_PHP_PHP中Closure类的使用方法及详解,Closure,匿名函数,又称为Anonym - phpStudy...
  16. 华科计算机组成原理 存储系统实验 汉字字库Logsim实验
  17. 用双重for循环打印99乘法表
  18. 向来痴,从此醉,先生一路走好。
  19. Arduino基础1
  20. UE4 Material_01:堡垒之夜砍伐树木效果

热门文章

  1. Clone this repository
  2. 2019年顶级开发笑话
  3. h3c防火墙u200配置命令_H3C SecPath U200-CA U200-CM U200-CS新一代多功能防火墙 安装指导-6PW106...
  4. GLP实验室使用ELN电子记录的必要性
  5. 软件测试之数据库表清理,软件测试之数据库系列三
  6. 手机或模拟器不能连接adb 原因罗列(持续更新)
  7. event事件冒泡之cancelBubble和stoppropagation的区别
  8. 宝塔面板在同一服务器下创建多个端口部署项目(轻量应用服务器一键部署网站、博客、GltLab完整版)
  9. HTML - 元素/标签详解
  10. DDNS配置实例(DHCP+DNS=DDNS)