Golang语言系列-06-map数据类型和指针
Map数据类型和指针
Map数据类型
Map基本概念
package main
import "fmt"
// map
// make()函数和new()函数的区别
// make和new都是用来申请内存的
// new很少用,一般用来给基本数据类型申请内存,`string`、`int`,返回的是对应类型的指针(*string、*int)
// make是用来给`slice`、`map`、`chan`申请内存的,make函数返回的的是对应的这三个类型本身
func main() {
var m1 map[string]int
fmt.Println(m1 == nil) //true 还没初始化,没有在内存中开辟空间
m1 = make(map[string]int, 10) //要估算好改map的容量,避免在程序运行期间再动态扩容,影响性能
fmt.Println(m1 == nil) //false 已经在内存中开辟空间了
m1["age"] = 18
m1["salary"] = 2000
fmt.Println(m1)
fmt.Println(m1["salary"])
// 不存在的键
// 约定成俗用ok接收返回的布尔值
fmt.Println(m1["tom"]) //如果不存在这个key,则拿到对应值类型的零值 0
value, ok := m1["tom"]
if !ok {
fmt.Println("没有此key")
} else {
fmt.Println(value)
}
// map的遍历
for k, v := range m1 {
fmt.Println(k, v)
}
// 只遍历key
for k := range m1 {
fmt.Println(k)
}
// 只遍历value
for _, v := range m1 {
fmt.Println(v)
}
// 删除
delete(m1, "salary")
fmt.Println(m1)
delete(m1, "tom") //删除不存在的key,程序也不会报错
}
练习
package main
import (
"fmt"
"math/rand"
"sort"
"time"
)
// 让map按照key排序打印
func main() {
rand.Seed(time.Now().UnixNano()) //初始化随机数种子
var scoreMap = make(map[string]int, 100) //定义一个map,key为string类型,值为int类型
for i := 0; i < 50; i++ {
key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
value := rand.Intn(100) //生成0-99的随机整数
scoreMap[key] = value
}
fmt.Println(scoreMap, len(scoreMap))
// 取出map中所有的key存入切片keys
var keys = make([]string, 0, 100)
for key := range scoreMap {
keys = append(keys, key)
}
//fmt.Println(keys)
//sort.Ints() //按照整型排序
sort.Strings(keys) //按照字符串排序
//按照排序后的key遍历map
for _, key := range keys {
fmt.Println(key, scoreMap[key])
}
}
map和slice切片组合练习
package main
import (
"fmt"
)
// map和slice组合
func main() {
// 元素类型为map的切片
var s1 = make([]map[string]int, 10, 10) //切片的元素类型为map,长度10,容量10,切片已经初始化,但是里面的map类型没有初始化
fmt.Println(s1) //[map[] map[] map[] map[] map[] map[] map[] map[] map[] map[]]
// s1[0]的map类型初始化
s1[0] = make(map[string]int, 10)
fmt.Printf("%T %d\n", s1[0], len(s1[0])) //map[string]int 0
s1[0]["沙河"] = 10 //s1[0]表示map,s1[0]["沙河"]表示map的key为沙河
fmt.Printf("s1:%T s1[0]:%T\n", s1, s1[0]) //s1:[]map[string]int s1[0]:map[string]int 注意这里s1是切片;s1[0]是map
fmt.Println(s1) //[map[沙河:10] map[] map[] map[] map[] map[] map[] map[] map[] map[]]
// s1[1]的map初始化
s1[1] = make(map[string]int)
s1[1]["kobe"] = 24
s1[1]["duke"] = 21
fmt.Println(s1) //[map[沙河:10] map[duke:21 kobe:24] map[] map[] map[] map[] map[] map[] map[] map[]]
// 值为切片类型的map
var m1 = make(map[string][]int) //key是string类型,值是[]int int切片类型
m1["北京"] = []int{1, 2, 3}
m1["上海"] = []int{4, 5}
fmt.Println(m1) //map[上海:[4 5] 北京:[1 2 3]]
}
指针
package main
import "fmt"
// point 指针
// go语言中不会直接进行指针的运行,因此只要会使用 & * 基本上就够了
// make和new的区别
// make和new都是用来申请内存的
// new很少用,一般用来给基本数据类型申请内存,`string`、`int`,返回的是对应类型的指针(*string、*int)
// make是用来给`slice`、`map`、`chan`申请内存的,make函数返回的的是对应的这三个类型本身
func main() {
// 1. &:取内存地址
n := 18
p := &n //&n 取n变量在内存中的地址,并且赋值给p变量
fmt.Println(p) //0xc00001a070 n变量在内存中的地址
fmt.Println(&n) //0xc00001a070 n变量在内存中的地址
fmt.Println(*p) //取值 18
fmt.Println(*(&n)) //18
fmt.Printf("%T\n", p) //*int:int类型的指针
fmt.Println(&p) //0xc00000e028 p变量自己在内存中的地址
fmt.Println(*(&p)) //0xc00001a070 取p变量指向的值,即n的内存地址
// 2. *:根据地址取值
m := *p //这个是取出p变量中存放的n的内存地址所指向的值
fmt.Println(m) //18
fmt.Printf("%T\n", m) //int
pn := &p //&p p变量自己在内存中的地址
fmt.Printf("%p\n", pn) //0xc00008c018 p变量自己在内存中的地址
fmt.Println("----------------------------------")
var a1 *int //nil pointer 未申请内存地址
fmt.Println(a1) //<nil>
var a2 = new(int) //new函数申请一块内存地址
fmt.Println(a2) //0xc00001a078 这是一块内存地址
fmt.Println(*a2) //获取这块内存地址指向的值是多少 //0
*a2 = 100 //给这块内存地址赋值
fmt.Println(*a2) //100
fmt.Println(&a2) //0xc0000ae028 a2在内存中的地址
}
package main
import "fmt"
/*
[pointer指针]
Go语言中的指针不能进行偏移和运算,是安全指针
要搞明白Go语言中的指针需要先知道3个概念:指针地址、指针类型和指针取值
[Go语言中的指针]
任何程序数据载入内存后,在内存都有他们的地址,这就是指针.而为了保存一个数据在内存中的地址,我们就需要指针变量
比如,“永远不要高估自己”这句话是我的座右铭,我想把它写入程序中,程序一启动这句话是要加载到内存(假设内存地址0x123456),
我在程序中把这段话赋值给变量A,把内存地址赋值给变量B。
这时候变量B就是一个指针变量。
通过变量A和变量B都能找到我的座右铭
Go语言中的指针不能进行偏移和运算,因此Go语言中的指针操作非常简单,我们只需要记住两个符号:
&(取地址)和 *(根据地址取值)
总结: 取地址操作符&和取值操作符*是一对互补操作符,&取出地址,*根据地址取出地址指向的值
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
对变量进行取地址(&)操作,可以获得这个变量的指针变量。 //a := 10 b := &a
指针变量的值是指针地址。 //b的值是指针地址
对指针变量进行取值(*)操作,可以获得指针变量指向的原变量的值。 // *b 的值是10
[new和make]
在Go语言中对于引用类型的变量,我们在使用的时候不仅要声明它,还要为它分配内存空间,否则我们的值就没办法存储。
而对于值类型的声明不需要分配内存空间,是因为它们在声明的时候已经默认分配好了内存空间。
要分配内存,就引出来今天的new和make
Go语言中new和make是内建的两个函数,主要用来分配内存
new
new是一个内置的函数,它的函数签名如下:
func new(Type) *Type
Type表示类型,new函数只接受一个参数,这个参数是一个类型
*Type表示类型指针,new函数返回一个指向该类型内存地址的指针
new函数不太常用,使用new函数得到的是一个类型的指针,并且该指针对应的值为该类型的零值
func main() {
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
}
make
make也是用于内存分配的,区别于new,它只用于slice、map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,
因为这三种类型就是引用类型,所以就没有必要返回他们的指针了
make函数是无可替代的,我们在使用slice、map以及channel的时候,都需要使用make进行初始化,然后才可以对它们进行操作
new与make的区别
二者都是用来做内存分配的
make只用于slice、map以及channel的初始化,返回的还是这三个引用类型本身
new用于类型的内存分配,并且内存对应的值为类型零值,返回的是指向类型的指针
*/
func main() {
var a int
a = 100
b := &a //b是获取了a的内存地址 指针
//fmt.Printf("type a:%T type b:%T\n", a, b)
//fmt.Println("b:", b) //0xc000018080
//
fmt.Printf("%p\n", &a) //a的内存地址或者说指针 0xc000018080
fmt.Printf("%p\n", b) //a的内存地址或者说指针 0xc000018080
fmt.Printf("%#v\n", b) //b的值 (*int)(0xc000018080) b这个变量存储的值就是a的内存地址
fmt.Printf("%p\n", &b) //b自己本身内存地址 0xc0000ae018
fmt.Printf("%v\n", *b) //100 查找b这个变量的值(a的内存地址) 所指向的值
}
小练习
写一个程序,统计一个字符串中每个单词出现的次数。比如:”how do you do”中 how=1 do=2 you=1
package main
import (
"fmt"
"strings"
)
// 写一个程序,统计一个字符串中每个单词出现的次数。比如:”how do you do”中how=1 do=2 you=1
func main() {
s1 := "how do you do"
s2 := strings.Split(s1, " ") //返回 []string 切片
// 定义一个map并且初始化
var m1 = make(map[string]int, 100) //初始化以后int类型的零值为0
for _, key := range s2 {
//m1[key] = m1[key] + 1
m1[key]++
}
fmt.Println(m1)
}
回文判断
package main
import "fmt"
func main() {
// 回文判断 字符串从左往右读和从右往左读是一样的,那么就是回文。
// 上海自来水来自海上 s[0] s[len(s)-1]
// 山西运煤车煤运西山
ss := "a山西运煤车煤运西山a"
r := make([]rune, 0, 255) //初始化 []rune切片 长度0,容量255
// 把字符串中的字符拿出来放到一个切片中
for _, c := range ss {
r = append(r, c)
}
// 此时的切片r: [97 23665 35199 36816 29028 36710 29028 36816 35199 23665 97]
for i := 0; i < len(r)/2; i++ {
if r[i] != r[len(r)-1-i] {
fmt.Printf("字符串 [%s] 不是回文\n", ss)
return
}
}
fmt.Printf("字符串 [%s] 是回文\n", ss)
}
Golang语言系列-06-map数据类型和指针的更多相关文章
- Golang语言系列-02-常用数据类型
Go语言常用数据类型 Go 语言中有丰富的数据类型,除了基本的整型.浮点型.布尔型.字符串.byte/rune 之外, 还有数组.切片.函数.map.通道(channel).结构体等. Go语言的基本 ...
- Golang语言系列-08-结构体
结构体 自定义类型和类型别名的区别 package main import "fmt" // 自定义类型和类型别名的区别 // type后面跟的是类型 type myInt int ...
- C语言-06复杂数据类型-03指针
指针变量的定义 变量类型 *变量名; #include <stdio.h> int main() { // 指针就一个作用:能够根据一个地址值,访问对应的存储空间 // 指针变量p前面的i ...
- Golang语言系列-10-包
包 自定义包 package _0calc import ( "fmt" ) /* [Go语言的包] 在工程化的Go语言开发项目中,Go语言的源码复用是建立在包(package)基 ...
- Golang语言系列-11-goroutine并发
goroutine 并发 概念 package main import ( "fmt" "time" ) /* [Go语言中的并发编程 goroutine] [ ...
- Golang语言系列-07-函数
函数 函数的基本概念 package main import ( "fmt" ) // 函数 // 函数存在的意义:函数能够让代码结构更加清晰,更简洁,能够让代码复用 // 函数是 ...
- Golang语言系列-09-接口
接口 接口的定义和实现 package main import "fmt" /* [接口] 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现 ...
- Golang语言系列-05-数组和切片
数组和切片 数组 概念 数组是同一种数据类型元素的集合:数组的长度必须是常量,并且长度是数组类型的一部分,一旦定义,长度不能变 例如:[5]int 和 [10]int 是不同的数组类型 使用时可以修改 ...
- Golang语言系列-01-Go语言简介和变量
Go语言简介 Go(又称Golang)是Google开发的一种静态强类型.编译型.并发型,并具有垃圾回收功能的编程语言. 罗伯特·格瑞史莫(Robert Griesemer),罗勃·派克(Rob Pi ...
随机推荐
- 小程序开发 access_token 统一管理
TOKEN 定时刷新器 一.背景 对于使用过公众平台的API功能的开发者来说,access_token绝对不会陌生,它就像一个打开家门的钥匙,只要拿着它,就能使用公众平台绝大部分的API功能.因此,对 ...
- Docker:docker创建容器时报错:WARNING: IPv4 forwarding is disabled. Networking will not work.
创建容器时报错: WARNING: IPv4 forwarding is disabled. Networking will not work. # docker run -it -p 30001:2 ...
- 在 Docker 上配置 Oracle
地址:https://github.com/wnameless/docker-oracle-xe-11g .直接 git clone 到本地就行了 ##安装 docker shell 下: docke ...
- awk中printf的用法
printf函数 打印输出时,可能需要指定字段间的空格数,从而把列排整齐.在print函数中使用制表符并不能保证得到想要的输出,因此,可以用printf函数来格式化特别的输出. printf函数返 ...
- Java实验项目四——多线程矩阵相乘算法的设计
Program:多线程矩阵相乘算法的设计 Description:利用多线程实现矩阵相乘,因为各个线程的运算互不影响, 所以不用使用锁,代码如下: thread.OperateMatrix类,实现矩阵 ...
- hdu 2092 整数解(一元二次方程解)
题目: 思路: 1.两个整数的和和积容易联想到一元二次方程的两个根,只要证明有两个解,并都是整数就打印出Yes,否则打印出No 2.最后判断那步,为什么只需要判断一个整数存在就够了,因为和是整数,一个 ...
- git常用命令自己梳理总结
一.新建代码库 # git-init - 创建一个空的 Git 存储库或重新初始化一个现有的存储库 $ git init # 在本地新建一个repo,进入一个项目目录,执行git init,会初始化一 ...
- 【Git】pull遇到错误:error: Your local changes to the following files would be overwritten by merge:
这种情况下,如何保留本地的修改同时又把远程的合并过来呢? 首先取决于你是否想要保存本地修改.(是 /否) 是 git stash git pull origin master git stash po ...
- C语言:case详解
C语言虽然没有限制 if else 能够处理的分支数量,但当分支过多时,用 if else 处理会不太方便,而且容易出现 if else 配对出错的情况.例如,输入一个整数,输出该整数对应的星期几的英 ...
- C语言:char总结
char字符型数据1.用单引号限制的1字节的字符称为字符型数据,字符型常量2.字符型常量实质保存的是对应字符的ASCII码值,是一个整数3.字符型常量表示范围:0-2554.声明字符型变量 char ...