变量&常量
变量
-
命名
由字母、数字、下划线组成,首个字符不能是数字关键字、保留字不能作为变量名变量名字区分大小写驼峰命名
-
声明
1. var : 全局变量var 变量名称 类型var 变量名称1,变量名称2 类型 (同一种类型)var (变量名称1 类型1变量名称2 类型2)2. 短变量声明( := ) : 局部变量变量名称 := 类型变量名称1, 变量名称2 := 类型1, 类型2变量声明后没有初始化,值为空变量需要声明后才能使用,同一作用域不支持重复声明
常量
-
声明
const 常量名称 = 值const (常量名称1 = 值1常量名称2 = 值2常量名称3 (省略赋值则为上一个 : 值二))常量声明时必须赋值且不可改变
数据类型
-
整型
默认为0int8(-128 - 127), int16, int32, int64uint8(0 - 255), uint16, uint32, uint64int类型转换:int8(), int16(), int32(), int64()数字字面量语法:fmt.Printf("%d:10进制输出 %b:2进制输出 %o:8进制输出 %x:16进制输出")
-
浮点型
默认为0float32, float64fmt.Printf("%.nf:保留n位小数")精度丢失:第三方包(decimal)解决float 转 int:int()int 转 float:float32()
-
布尔型
true, false(默认)不允许将整形强制转换为布尔型布尔型无法参与数值运算,也无法与其他类型进行转换
-
字符串
默认为空: ""转义字符: \r:回车符(返回行首) \n:换行符 \t:制表符 \':单引号 \":双引号 \\: 斜杠多行字符串: ``常用操作:len(str): 求长度+ 或 fmt.Sprint: 拼接字符串strings.Split: 切割strings.contains: 判断是否包含strings.HasPrefix, strings.HasSuffix: 前缀、后缀判断strings.Index(), strings.LastIndex(): 字串出现的位置strings.Join()其他类型 转 字符串:fmt.Sprint()strconv
-
byte&rune
byte: uint8,代表ASCII码的一个字符rune: int32,代表一个UTF-8字符汉字占用3个字节,字母占用一个字节遍历字符串:for i := 0; i < len(str); i++ { //bytefmt.Println(str[i])}for _, i := range str { //runefmt.Println(i)}
-
数组
数组的长度必须是常量,并且长度是数组的一部分,不能改变var 数组名 [n]类型var 数组名 [...]类型{值, 值, ...}var 数组名 [...]类型{索引值: 值, 索引值: 值, ...}遍历:for i, v := range arr {// i 索引值, v 值}值类型:改变变量副本值的时候,不会改变变量本身的值引用类型:改变变量副本值的时候,会改变变量本身的值基本数据类型 和 数组都是值类型
-
切片
切片的长度可以改变var 切片名 []类型[l:r]: 获取切片值扩容: append()复制切片(不影响原切片):copy()删除: append([:n], [n:]...) 删除索引为n修改: 转换为byte或rune, 再进行修改排序: sort
-
map
无序 key: valuemake(map[类型]类型)map[类型]类型{key: value}遍历:for k, v := range map {// k键, v 值}获取: v, ok := map[key] //ok(true || false)删除: delete(map, key)排序: 把key存入切片,将切片排序
运算符
-
算术运算符
+ - * / %(被除数 - (被除数/除数) * 除数)++、-- 是单独的语句,并不是运算符
-
关系运算符
== != > < >= <=
-
逻辑运算符
&& || !
-
赋值运算符
= += -= *= /= %=
流程控制
-
if else
if 表达式 {分支1} else if 表达式 {分支2} else {分支3}
-
for
for 初始语句(可省略); 条件表达式; 结束语句(可省略) {循环体语句}
-
switch
switch expression {case condition: 语句 break(可以不写)case condition1, condition2: 语句 breakdefauit: 语句 }
-
break&continue
label1:for xxx {for yyy {break label1 //跳出label1continue label1 //结束本次label1}}
-
goto
goto label1xxxlabel1:yyygoto跳转到label1
函数
-
定义
func 函数名 (参数 类型, 可变参数 ...类型) (返回值 类型){函数体}返回值命名: 函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return返回
-
类型与匿名函数
type 函数类型名 func(参数 类型) 返回值匿名自执行函数: func(参数) 返回值{} (参数)
-
闭包
全局变量特点: 常驻内存,污染全局局部变量特点: 不常驻内存,不污染全局闭包: 常驻内存,不污染全局func 函数名() func() 类型 {return func() (返回值 类型) {return}}
-
defer
defer 会将其后面跟随的语句进行延迟处理,return之前逆序执行(最后的语句,最先执行)return x: 1. 返回值 = x 2. 运行defer3. RET指令
-
panic & recover
panic(): 可以在任何地方抛出异常recover(): 只能在defer调用的函数中接收异常 panic("err")defer func() {err := recover()}
指针
指针是一个变量,存储另一个变量的内存地址
定义: &变量 取值: *变量
结构体
type 类型名 struct {字段名 字段类型
}结构体函数:type Fxm intfunc (Fxm) 函数名() {}匿名字段: 声明时没有字段名只有类型(同种类型的匿名字段只有一个)结构体的类型是指针、切片、map时,如要使用,需要先makejson转换:jsonByte := json.Marshal() (私有变量不能被json包访问) (生成字节切片)jsonStr := string(jsonByte)结构体标签:type Fxm struct {Id int `json:"id"`}
接口
type 接口名 interface {方法名(参数) 返回值
}空接口: 接口中不定义任何方法,可以表示任意数据类型
map的值、切片可以是空接口类型类型断言: (.(type)只能结合switch使用)switch v := interface1.(type) {case string: xxx}值接收者: 实例化后的结构体值类型和结构体指针类型都可以赋值给接口变量
指针接收者: 实例化后的结构体指针类型可以赋值给接口变量,结构体值类型不可
并发&并行
-
协程
goroutine: go 函数名等待goroutine执行完毕:var wg = sync.WaitGroupwg.Add(1) //协程计数器加1wg.Done(1) //协程计数器加-1wg.Wait() //等待协程执行完毕获取当前计算机cpu个数runtime.NumCPU()设置使用cpu个数runtime.GoMAXPROCS(cpu个数)
-
管道Channel
管道是goroutine之间的通讯方式,先入先出Golang 的并发模型是CSP,提倡通过通信共享内存,而不是通过内存实现通信
-
channel
channel是一种引用类型声明: var 变量名 chan 类型管道声明后需要make初始化之后才能使用make(chan 类型, 容量)管道的发送和接收使用 <-发送: channel1 <- 值接收: 值 := <- channel1关闭: close(channel1)遍历管道: for(管道没有key)
-
单向管道
默认是双向只写: make(chan<- 类型, 容量)只读: make(<-chan 类型, 容量)
-
多路复用 select
同时从多个管道获取数据,不需要关闭管道select{case 值 := <- channel1: xxxcase channel2 <- 值: xxxdefault: xxx}
-
互斥锁
sync.Mutex: Lock() Unlock()
-
读写互斥锁
可以让多个读操作并发,但写操作是互斥的sync.RWMutex写操作: Lock() Unlock()读操作: RLock() RUnlock()
反射
需求: 一个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,可能这个类型不存在
反射: 在程序运行期间对程序本身进行访问和修改的能力
支持反射的语言可以在程序编译期将变量的反射信息整合到可执行文件,并给程序提供接口访问反射信息
-
reflect
Go中的变量分为两部分: 类型信息、值信息reflect.TypeOf() //Name、Kindreflect.ValueOf()修改: Elem().Setxxx()
文件
-
读取文件:
file, err := os.Open(文件名) //只读defer file.Close()file.Read()file, err := os.Open(文件名) //只读defer file.Close()reader := bufio.NewReader(file)line, err := reader.ReadString('\n')ioutil.ReadFile(文件名)
-
写入文件:
file, err := os.OpenFile(文件名, os.O_CREATE|os.O_RDWR, 0666)defer file.Close()file.Write([]byte(str))file.WriteString(str)file, err := os.OpenFile(文件名, os.O_CREATE|os.O_RDWR, 0666)defer file.Close()writer := bufio.NewWriter(file)writer.WriteString(str)writer.Flush()ioutil.WriteFile(文件名, []byte(str), 0666)
-
文件操作:
文件重命名: os.Rename(原文件名,文件名)复制文件: file, err := ioutil.ReadFile(原文件)ioutil.WriteFile(文件名, file, 0644)创建目录:os.Mkdir(目录名, 0666)删除目录和文件:os.Remove(文件名)os.RemoveAll(目录名)
其他
-
查看环境变量
go env
-
设置GOPROXY代理
go env -w GOPROXY=https://goproxy.io,direct
-
更新go.sum
go mod tidy
-
下载第三方包
1. go get 包名(全局,不建议) 2. go mod download(全局,建议) 3. go mod vendor(下载到项目中)
-
定时器
time.NewTicker()time.Slwwp()
-
初始化项目
go mod init 项目名()
-
大小写:
首字母小写:私有变量、私有方法首字母大写:公有变量、公有方法
-
导入
import 别名 包名import _ 包名:匿名引入
-
init
最先执行最后导入包的init
-
第三方包网站
https://pkg.go.dev/
小问题
-
main.go 导包找不到
如下图片添加:https://goproxy.io