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
", 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
", 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
",arrString,arrString)
//slice的声明方式一,直接从数组里面切出来
sliceByArray := arrString[0:]
fmt.Printf("type:%T
", sliceByArray)
//slice的声明方式二,通过make
sliceByMake := make([]string,10)
sliceByMake[0] = "啦啦啦"
sliceByMake[1] = "阿拉蕾"
fmt.Printf("type:%T,value:%v
",sliceByMake,sliceByMake)
//slice的声明方式三,定义个切片
slices := []string{
"嗯哼",
"是的",
}
fmt.Printf("type:%T,value:%v
",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
",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()是给引用类型申请内存空间。