变量&常量
变量
-
命名
由字母、数字、下划线组成,首个字符不能是数字 关键字、保留字不能作为变量名 变量名字区分大小写 驼峰命名
-
声明
1. var : 全局变量 var 变量名称 类型 var 变量名称1,变量名称2 类型 (同一种类型) var ( 变量名称1 类型1 变量名称2 类型2 ) 2. 短变量声明( := ) : 局部变量 变量名称 := 类型 变量名称1, 变量名称2 := 类型1, 类型2 变量声明后没有初始化,值为空 变量需要声明后才能使用,同一作用域不支持重复声明
常量
-
声明
const 常量名称 = 值 const ( 常量名称1 = 值1 常量名称2 = 值2 常量名称3 (省略赋值则为上一个 : 值二) ) 常量声明时必须赋值且不可改变
数据类型
-
整型
默认为0 int8(-128 - 127), int16, int32, int64 uint8(0 - 255), uint16, uint32, uint64 int类型转换: int8(), int16(), int32(), int64() 数字字面量语法: fmt.Printf("%d:10进制输出 %b:2进制输出 %o:8进制输出 %x:16进制输出")
-
浮点型
默认为0 float32, float64 fmt.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++ { //byte fmt.Println(str[i]) } for _, i := range str { //rune fmt.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: value make(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: 语句 break defauit: 语句 }
-
break&continue
label1: for xxx { for yyy { break label1 //跳出label1 continue label1 //结束本次label1 } }
-
goto
goto label1 xxx label1: yyy goto跳转到label1
函数
-
定义
func 函数名 (参数 类型, 可变参数 ...类型) (返回值 类型){ 函数体 } 返回值命名: 函数定义时可以给返回值命名,并在函数体中直接使用这些变量,最后通过return返回
-
类型与匿名函数
type 函数类型名 func(参数 类型) 返回值 匿名自执行函数: func(参数) 返回值{} (参数)
-
闭包
全局变量特点: 常驻内存,污染全局 局部变量特点: 不常驻内存,不污染全局 闭包: 常驻内存,不污染全局 func 函数名() func() 类型 { return func() (返回值 类型) { return } }
-
defer
defer 会将其后面跟随的语句进行延迟处理,return之前逆序执行(最后的语句,最先执行) return x: 1. 返回值 = x 2. 运行defer 3. RET指令
-
panic & recover
panic(): 可以在任何地方抛出异常 recover(): 只能在defer调用的函数中接收异常 panic("err") defer func() { err := recover() }
指针
指针是一个变量,存储另一个变量的内存地址
定义: &变量 取值: *变量
结构体
type 类型名 struct {
字段名 字段类型
}
结构体函数:
type Fxm int
func (Fxm) 函数名() {}
匿名字段: 声明时没有字段名只有类型(同种类型的匿名字段只有一个)
结构体的类型是指针、切片、map时,如要使用,需要先make
json转换:
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.WaitGroup wg.Add(1) //协程计数器加1 wg.Done(1) //协程计数器加-1 wg.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: xxx case channel2 <- 值: xxx default: xxx }
-
互斥锁
sync.Mutex: Lock() Unlock()
-
读写互斥锁
可以让多个读操作并发,但写操作是互斥的 sync.RWMutex 写操作: Lock() Unlock() 读操作: RLock() RUnlock()
反射
需求: 一个函数有能力统一处理各种值类型,而这些类型可能无法共享同一个接口,可能这个类型不存在
反射: 在程序运行期间对程序本身进行访问和修改的能力
支持反射的语言可以在程序编译期将变量的反射信息整合到可执行文件,并给程序提供接口访问反射信息
-
reflect
Go中的变量分为两部分: 类型信息、值信息 reflect.TypeOf() //Name、Kind reflect.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(目录名)
其他
-
代理
https://goproxy.io/
-
定时器
time.NewTicker() time.Slwwp()
-
初始化项目
go mod init 项目名()
-
大小写:
首字母小写:私有变量、私有方法 首字母大写:公有变量、公有方法
-
导入
import 别名 包名 import _ 包名:匿名引入
-
init
最先执行最后导入包的init
-
第三方包
https://pkg.go.dev/
-
下载第三方包
1. go get 包名(全局,不建议) 2. go mod download(全局,建议) 3. go mod vendor(下载到项目中)