Go的数据类型
1.map
map 是 key-value 数据类型
//map 使用之前一定要make一下 maps := make(map[string]string, 10) maps["hero1"] = "张三" maps["hero2"] = "李四" maps["hero3"] = "王五" //取值,第一个参数是返回值,第二个参数是错误,用值的时候,要判断一下错误是否存在 hero4, ok := maps["hero4"] if ok { fmt.Printf("hero4:%v", hero4) } else { fmt.Println("hero4 don't exist.") }
1) map 再使用前一定要make
2) map 的key 是不能重复的,如果重复了,则会覆盖前的的key
3) map 的 value 是可以相同的
4) map 的key-value 是无序的
5) map 是不支持并发的,也就是多个goroutine同时取值和设值的时候会报错,推荐使用sync.Map,支持并发,本质是加锁
package main import ( "fmt" "sync" ) //map 使用要make一下 var maps = make(map[string]string, 10) // sync.Map 开箱即用,就是声明之后就可以用了 var syncMap sync.Map //获取值 func get(key string) string { return maps[key] } //设置值 func set(key string, value string) { maps[key] = value } // 不使用syncMap func dontUseSyncMap() { var wg sync.WaitGroup for i := 0; i < 20; i++ { wg.Add(1) // 模拟多个goroutine同时取值和设值,会报错 go func(index int) { defer wg.Done() set(string(index), string(index)) fmt.Printf("%v --- %v\n", index, get(string(index))) }(i) } wg.Wait() fmt.Println("ok!~") } //使用sync.Map func useSyncMap() { var wg sync.WaitGroup for i := 0; i < 100; i++ { wg.Add(1) go func(index int) { defer wg.Done() syncMap.Store(string(index), string(index)) val, _ := syncMap.Load(string(index)) fmt.Printf("%v --- %v\n", index, val) }(i) } wg.Wait() fmt.Println("ok!~") } func main() { //dontUseSyncMap() //useSyncMap() }
2.数组
数组是存放多个同一类型的数据,数组也是一种数据类型,在Go中,数组是值类型
//定义一个存放10个string类型的数组 var arr [10] string arr[0] = "你好" arr[1] = "真好" //定义一个存放5个string类型的数组 var arr2 [5] string arr2[0] = "你好" arr2[1] = "真好" //快速声明数组 arrString := [...]string{ "1", "2", "3", }
1) [10] string 和 [5] string 都是string的类型的数组,即使都是存放string类型,但是存放的个数不一样,就不是同一数据类型,Go语言是严格区分数据类型的
2) 数组是通过下标的访问的,下标从0开始
3.slice (切片)
slice可以理解成动态数组,容量的可以动态变化的,也就是存放的个数不限制
//快速声明数组 arrString := [...]string{ "1", "2", "3", } fmt.Printf("type:%T,value:%v\n",arrString,arrString) //slice的声明方式一,直接从数组里面切出来 sliceByArray := arrString[0:] fmt.Printf("type:%T\n", sliceByArray) //slice的声明方式二,通过make sliceByMake := make([]string,10) sliceByMake[0] = "啦啦啦" sliceByMake[1] = "阿拉蕾" fmt.Printf("type:%T,value:%v\n",sliceByMake,sliceByMake) //slice的声明方式三,定义个切片 slices := []string{ "嗯哼", "是的", } fmt.Printf("type:%T,value:%v\n",slices,slices)
1) slice也是通过下标去访问
4.struct (结构体)
//定义一个struct type Person struct { Name string Age int }
1) struct 其实就是OOP里面的类,相当于Java里面的Class
5.channel (管道)
channel 是引用类型,必须初始化之后才能使用,也就是要make一下
//创建一个channel 存放string类型的数据 channel := make(chan string,10) //往channel 里面存数据 //注意,存数据的时候,如果超出容量的话,是会保存的,要考虑好管道里面数据的流动,即是有进有出 channel <- "你好吖" //从channel 里面取数据 <- channel fmt.Printf("channel len:%v ; cap=%v \n",len(channel),cap(channel))
1) channel 里面存放指定的数据类型
2) channel 的数据放满后,就不能再继续存放了,只有从里面取出数据,才能再存放数据了
3) 在没有使用协程的情况下,如果channel 数据取完了,再取,就会报 dead lock (死锁)
6.值类型和引用类型
1.值类型
值类型包括基本数据类型,int,float,bool,string,以及数组和结构体(struct)。
值类型变量声明后,不管是否已经赋值,编译器为其分配内存,此时该值存储于栈上。
var a int //int类型默认值为 0 var s string //string类型默认值为 nil空 var b bool //bool类型默认值为false var arr [2]int //数组默认值为[0 0] fmt.Println(&a) //通过&来取内存地址
2.引用类型
引用类型包括指针,slice切片,map ,chan,interface。
变量直接存放的就是一个内存地址值,这个地址值指向的空间存的才是值。
引用类型必须申请内存才可以使用,make()是给引用类型申请内存空间。