目录1.指针1.1指针地址和指针类型1.2指针取值1.3空指针1.4new的使用1.5new与make的区别2.Map2.1什么是Mapkey,value存储hash冲突hash冲突...
目录
1. 指针1.1 指针地址和指针类型
1.2 指针取值
1.3 空指针
1.4 new 的使用
1.5 new与make的区别
2. Map
2.1 什么是Map
key,value存储
hash冲突
hash冲突的常见解决方法
开放定址(线性探测)和拉链的优缺点
2.2 Map 定义
2.3 map基本使用
2.4 map的遍历
2.5 map判断某个键是否存在
2.6 map使用delete()函数删除键值对
1. 指针
区别于C/C++中的指针,Go语言中的指针不能进行偏移和运算,是安全指针。
要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值。
Go语言中的函数传参都是值拷贝,当我们想要修改某个变量的时候,我们可以创建一个指向该变量地址的指针变量。
传递数据使用指针,而无须拷贝数据。类型指针不能进行偏移和运算。
Go语言中的指针操作非常简单,只需要记住两个符号:&(取地址)和*(根据地址取值)。
1.1 指针地址和指针类型
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用javascript&字符放在变量前面对变量进行“取地址”操作。
Go语言中的值类型(int、float、bool、string、array、struct)都有对应的指针类型,如:*int、*int64、*string等。
取变量指针的语法如下:
ptr:=&v//v的类型为T
其中:
v:代表被取地址的变量,类型为Tptr:用于接收地址的变量,ptr的类型就为*T,称做T的指针类型。*代表指针。packagemain
import"fmt"
funcmain(){
a:=10
b:=&a
fmt.Printf("a:%dptr:%p\n",a,&a)//a:10ptr:0xc00001a078
fmt.Printf("b:%ptype:%T\n",b,b)//b:0xc00001a078type:*int
fmt.Println(&b)//0xc00000e018
}
1.2 指针取值
在对普通变量使用&操作符取地址后会获得这个变量的指针,然后可以对指针使用*操作,也就是指针取javascript值。
packagemain
import"fmt"
funcmain(){
//指针取值
a:=10
b:=&a//取变量a的地址,将指针保存到b中
fmt.Printf("typeofb:%T\n",b)
c:=*b//指针取值(根据指针去内存取值)
fmt.Printf("typeofc:%T\n",c)
fmt.Printf("valueofc:%v\n",c)
}
输出结果:
type of b: *int
type of c: int
value of c: 10
取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
对变量进行取地址(&)操作,可以获得这个变量的指针变量。指针变量的值是指针地址。
对指针变量进行取值(
*)操作,可以获得指针变量指向的原变量的值。packagemain
import"fmt"
funcp1(nint){
n=100
}
funcp2(n*int){
*n=100
}
funcmain(){
a:=10
p1(a)
fmt.Println(a)//10
p2(&a)
fmt.Println(a)//编程100
}
1.3 空指针
当一个指针被定义后没有分配到任何变量时,它的值为nil空指针的判断
packagemain
import"fmt"
funcmain(){
varp*string
fmt.Printf("p的值是%v\n",p)
ifp!=nil{
fmt.Println("非空指针")
}else{
fmt.Println("空指针")
}
}
1.4 new 的使用
new是一个内置的函数,它的函数签名如下:
funcnew(Type)*Type
其中:
Type表示类型,new函数只接受一个参数,这个参数是一个类型*Type表示类型指针,new函数返回一个指向该类型内存地址的指针。new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值。
funcmain(){
a:=new(int)
b:=new(bool)
fmt.Printf("%T\n",a)//*int
fmt.Printf("%T\n",b)//*bool
fmt.Println(*a)//0
fmt.Println(*b)//false
}
var a *int只是声明了一个指针变量a但是没有初始化,指针作为引用类型需要初始化后才会拥有内存空间,才可以给它赋值。应该按照如下方式使用内置的new函数对a进行初始化之后就可以正常对其赋值了:
funcmain(){
vara*int
a=new(int)
*a=10
fmt.Println(*a)
}
make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
1.5 new与make的区别
二者都是用来做内存分配的。make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身;而
new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针。2. Map
map是一种无序的基于key-value的数据结构,Go语言中的map是引用类型,必须初始化才能使用。
2.1 什么是Map
key,value存储
最通俗的话说:Map是一种通过key来获取value的一个数据结构,其底层存储方式为数组,在存储时key不能重复,当key重复时,value进行覆盖,我们通过key进行hash运算(可以简单理解为把key转化为一个整形数字)然后对数组的长度取余,得到key存储在数组的哪个下标位置,最后将key和value组装为一个结构体,放入数组下标处。
hash冲突
数组一个下标处只能存储一个元素,也就是说一个数组下标只能存储一对key,value, hashkey(xiaoming)=4占用了下标0的位置,假设我们遇到另一个key,hashkey(xiaowang)也是4,这就是hash冲突(不同的key经过hash之后得到的值一样),那么key=xiaowang的怎么存储?
hash冲突的常见解决方法
开放定址法: 也就是说当我们存储一个key,value时,发现hashkey(key)的下标已经被别key占用,那我们在这个数组中空间中重新找一个没被占用的存储这个冲突的key,那么没被占用的有很多,找哪个好呢?常见的有:线性探测法,线性补偿探测法,随机探测法,这里以线性探测为对比。拉链法: 何为拉链,简单理解为链表,当
key的hash冲突时,我们在冲突位置的元素上形成一个链表,通过指针互连接,当查找时,发现key冲突,顺着链表一直往下找,直到链表的尾节点,找不到则返回空。开放定址(线性探测)和拉链的优缺点
拉链法比线性探测处理简单线性探测查找是会被拉链法会更消耗时间
线性探测会更加容易导致扩容,而拉链不会
拉链存储了指针,所以空间上会比线性探测占用多一点
拉链是动态申请存储空间的,所以更适合链长不确定的
2.2 Map 定义
Go语言中 Map的定义语法如下:
map[KeyType]ValueType
其中:
KeyType: 表示键的类型。ValueType: 表示键对应的值的类型。map类型的变量默认初始值为nil,需要使用make()函数来分配内存。语法为:
make(map[KeyType]ValueType,[cap])
其中cap表示map的容量,该参数虽然不是必须的,但是我们应该在初始化map的时候就为其指定一个合适的容量。
2.3 map基本使用
map中的数据都是成对出现的,map的基本使用如下:
funcmain(){
scoreMap:=make(map[string]int,8)
scoreMap["张三"]=90
scoreMap["李四"]=100
fmt.Println(scoreMap)
fmt.Println(scoreMap["李四"])
fmt.Printf("typeofa:%T\n",scoreMap)
}
输出结果:
map[李四:100 张三:90]
100
type of a: map[string]int
map也支持在声明的时候填充元素:
funcmain(){
userInfo:=map[string]string{
"username":"admin",
"password":"123456",
}
fmt.Println(userInfo)
}
2.4 map的遍历
Go语言中使用for range遍历map:
funcmain(){
scoreMap:=make(map[string]int)
scoreMap["张三"]=90
scoreMap["李四"]=100
scoreMap["王五"]=60
fork,v:=rangescoreMap{
fmt.Println(k,v)
}
}
如果只想遍历key的时候,可以按下面的写法:
funcmain(){
scoreMap:=make(map[string]int)
scoreMap["张三"]=90
scoreMap["李四"]=100
scoreMap["王五"]=60
fork:=rangescoreMap{
fmt.Println(www.cppcns.comk)
}
}
注意: 遍历map时的元素顺序与添加键值对的顺序无关。
2.5 map判断某个键是否存在
Go语言中有个判断map中键是否存在的特殊写法,格式如下:
value,ok:=map[key]
如果key存在ok为true,value为对应的值;不存在ok为false,value为值类型的零值
funcmain(){
scoreMap:=make(map[string]int)
scoreMap["张三"]=90
scoreMap["李四"]=100
//如果key存在ok为true,value为对应的值;不存在ok为false,value为值类型的零值
value,ok:=scoreMap["张三"]
ifok{
fmt.Println(v)
}else{
fmt.Println("查无此人")
}
}
2.6 map使用delete()函数删除键值对
使用delete()内建函数从map中删除一组键值对, delete()函数的格式如下:
delete(map,key)
其中:
map: 表示要删除键值对的mapkey: 表示要删除的键值对的键funcmain(){
scoreMap:=make(map[string]int)
scoreMap["张三"]=90
scoreMap["李四"]=100
scoreMap["王五"]=60
delete(scoreMap,"李四")//将李四:100从map中删除
fork,v:=rangescoreMap{
fmt.Println(k,v)
}
}
以上就是Go语言快速入门指针Map使用示例教程的详细内容,更多关于Go语言入门指针Map教程的资料请关注我们其它相关文章!










