go学习笔记
go语言中nil为空
go语言支持跨平台编译
windows编译linux:
SET CGO_ENABLE=0
SET GOOS=linux //系统
SET GOARCH=amd64 //架构
变量:
批量赋值:
var (
变量名1 变量类型
变量名2 变量类型
)
var 变量名 变量类型
在方法中声明的变量必须被使用(不包含被赋值),否则编译报错
简短变量声明(只能在函数):变量名:= 初始值
多重赋值:变量1,变量2,。。。变量n = 值1,值2,。。。值n
匿名变量:使用下划线接受变量,代表忽略掉
同一个作用域不能重复声明。
常量计数器iota
每次出现新的const关键字时iota被重置为0,即如果采用批量赋值const,const中每新增一行(同一行多个常量声明不算)声明将使iota计数一次。但只要批量赋值结束并在其后有新的const定义,那么iota归0。
iota只能赋予const
数值 << 位数 二进制左移
整型变量
int 8 16 32 64
unint 8 16 32 64
不带位数的int和uint代表根据系统设置,32位系统为32位,64位系统为64位。
uintptr 无符号整型,用于存放一个指针
float
默认64位,float32(数字)定义32位float,不可直接相等
复数
complex64 实部和虚部都是32位
complex128 实部和虚部都是64位
字符串
默认utf8编码
单引号字符,双引号字符串
方法 | 介绍 |
---|---|
len(str) | 求长度 |
+,fmt.Springf | 拼接字符串 |
strings.Split | 分割字符串 |
strings.contains | 是否包含 |
修改字符串
字符串默认无法修改,如果修改要先要创建一个rune切片,相当于字符数组
变量名 := []rune(字符串)
变量名[i] = ‘字符’
rune切片或字符强制切换成字符串,string(切片或字符)
byte和rune
byte==uint8
rune代表一个utf8字符,相当于int32
类型转换
强制转换成类型(数值)
流程控制
if else
if 表达式1 {
}else if 表达式2 {
}else{
}
在表达式上定义的变量旨在if语句中有效。
for循环结构
for 初始语句;条件表达式;结束语句{
循环语句
}
switch语句
switch n {
case 1: {}
default:{}
}
goto和标签
标签
标签名:
代码
goto 跳转到指定标签
运算符
算术运算符:±*/%
关系运算符:== != <= >= > <
数组
var 名称 [长度]类型 只能定义在方法外部
数组长度是数组类型一部分。
var 名称 = [长度]类型{数据1,数据2…} 初始化数组
切片
切片是一个拥有相同类型元素的可变长度的序列,它是基于数组类型的一层封装。
声明:var name []T
切片属于引用类型
去数组切片: 切片名 = 数组[起始位置,终止位置] 终止位置内容不包括
切片分配初始化: var 切片 = make([]类型, 长度,容量) 容量必须大于等于长度
len(数组) 数组的当前所有元素个数
cap(数组) 容量:数组当前创建的容量大小,在新增内容时,如果大于当前容量,那么当前容量翻倍,在达到1024后将会1.25倍增长.
copy(目标, 源) 复制源到目标,目标的长度必须跟源当前元素数量保持否则,否则大于目标长度的部分将会被切割
切片的复制和切片都属于深拷贝,不会对以前的数组产生影响。
指针
go语言不存在指针操作。 &代表取地址 * *根据地址取值,取值时只能从被&赋值的变量里获取地址,不能直接取变量。
对于go中的引用类型必须声明和分配内存空间。
*类型 代表定义一个变量这个变量的值为其他变量的地址。 *号可以叠加,每叠加一层,多取一层地址。
var 变量名 = new(类型) 定义一个变量,新建一个内存空间并获取内存空间的指针,此时的变量的值为地址值,要想赋值必须通过 *变量名 = 值 赋值
new一般给基本数据类型申请空间,string、int返回对应类型指针。
map
map引用类型,必须初始化。
map[KeyType]ValueType
make(map[KeyType]ValueType , 容量) 尽量定义合适,避免动态扩充
value, ok = map变量[key] 获取value,ok代表是否获取成功(是否存在这个key)
map遍历(range遍历):for k,v := range map变量
range遍历时按顺序接受内容,要想遍历value,需要 for _,v := range 接受
delete(map, key) 删除map里key内容,无key则不会做任何处理。
make
make用于内存分配,只用于slice、map、chan(通道),需要make初始化,返回的是类型本身而不是指针。
函数
//返回值也可以定义为变量,返回时直接return会默认返回定义的返回值变量
//返回值可以有多个,同参数格式一致,返回后按顺序接受内容
//多个参数同意类型可直接在最后一个参数位置添加类型
//例如:参数1,参数2,参数3 类型, 参数4,参数5,参数6 类型
//变长参数 参数名 ...int。返回值不能使用变长。
func 函数名(参数名 参数类型)([返回值变量名] 返回值){
函数体
}
函数也可以作为参数类型,也可以赋值给变量
函数作为参数类型时,传入参数时必须保证类型(即函数定义格式一致)
将函数作为参数或变量时,通过 参数名()调用。
defer
将后面跟随的语句延迟处理,函数即将返回时,将所有被定义的defer语句逆序执行。defer语句后不能跟return
匿名函数
无函数名称的函数,一般用于直接赋值给变量。
立即执行函数:
//直接运行
func (参数)(返回值类型){
方法体
}(参数)
闭包
内部函数可以使用外部函数内容。
作用域
{}用于区分作用域
错误处理,panic/recover
panic:
1、内建函数
2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行
3、返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如函数G中存在要执行的defer函数列表,按照defer的逆序执行,这里的defer 有点类似 try-catch-finally 中的 finally
4、直到goroutine整个退出,并报告错误
recover:
1、内建函数
2、用来控制一个goroutine的panicking行为,捕获panic,从而影响应用的行为
3、一般的调用建议
a). 在defer函数中,通过recever来终止一个gojroutine的panicking过程,从而恢复正常代码的执行
b). 可以获取通过panic传递的error
简单来讲:go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。
结构体
自定义类型和类型别名
type 类型名称 基于类型(基本类型或方法)
type 类型别名 = 类型
结构体
type 类型名 struct {
字段名 字段类型
}
//匿名结构体,多用于方法内部临时场景
var s struct {
名称 变量类型
}
//匿名结构体
var s = struct {
结构体结构
}{
结构体实现
}
new(结构体类型)得到结构体类型的指针
结构体中匿名变量
如果结构体中的变量只有类型没有名称,可通过结构体变量名.类型调用匿名变量。
但是匿名变量类型都只能唯一存在,除非由非匿名的。
方法
go语言中的方法是一种作用域特定类型变量的函数。接收者相当于java中this或python的self.
方法相当于为某一个类型添加一个可调用的函数(此函数只为该类型所拥有),可通过接收者变量名称.方法名调用
func (接收者变量 接收者类型) 方法名 (参数列表)(返回参数){
函数体
}
标识符
标识符指的是函数名、类型名、方法名、变量名
go语言中标识符如果首字母大写,表示对外部可见。
接口
接口是一种类型。
定义:
type 名称 interface {
方法名()
方法名2(参数)
}
go语言中接口不需要主动实现,只要一个结构体中存在方法实现了接口中的方法,就认为继承了该接口。
如果结构体实现的方法位于多个接口,那么代表结构体实现了多个接口。
接口嵌套
type 接口名 interface {
接口1
接口2
}
空接口
空接口内没有方法,所有内容都认为实现了空接口。类似java的object
空接口作为value保存map任意类型值。
var map1 = make(map[string]interface{})
//map1可以接受任意类型值
包
一个文件夹下只能有一个包,同一包go文件不能在不同文件夹下
包名不可以和文件夹名称一样
包名为main的包为程序入口,编译时不包含main包的源代码不会得到可执行文件
使用import “包名” 导入包,导入是默认从gopath下src目录开始计算位置
import 别名 “包名”
匿名导入包: import _ “包路径”
init()函数
init()函数在程序执行导入包时会自动执行,相当于java的默认无参构造,无法主动调用。init()优先于main函数
最后导入包最先执行init()函数,相当于java中子类先执行构造方法。
文件操作
os.Open() 打开文件,返回一个*File和一个err,使用close方法关闭文件.err如果为空,代表文件打开成功,否则文件打开失败
*File.Read()读取内容,为字节数组类型
fileObj, err := os.Open(文件路径)
if err != null{
处理错误
}
defer fileObj.Close() //定义关闭文件。方法执行后关闭文件
var tmp = [128]byte //读取用字节数组
n, err = fileObj.Read(tmp[:]) //n为读取字节数
//处理读取错误信息
if err != nil {
}
//获取读取内容,将字节数组转换为字符串
string(tmp[:n])//n代表读取长度
bufio
缓冲区读取
reader = bufio.NewReader(文件对象)
reader.ReadString("") //读取字符串
ioutil
读取全部文件内容。
content, err := ioutil.ReadFile(路径)
string(content)获取内容
os.OpenFile指定模式打开
os.OpenFile(name string, flag int, perm FileMode)(*File,error){
name打开的文件名,flag打开模式
模式 | 含义 |
---|---|
os.O_WRONLY | 只写 |
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
perm:文件权限,一个八进制数。r(读)04,w(写)02,x(执行)01
Wirte和WriteString
读取文件指定位置
fileObj.Seek(int偏移量,int相对位置)
//相对位置为0代表从文件头计算偏移量
//相对位置为1代表从文件当前位置计算偏移量
//相对位置为2代表从文件末尾计算偏移量
获取有用户输入
fmt.Scanln(&变量名)
fmt.Scan()
使用bufio获取用户输入
reader = bufio.NewReader(os.Stdin)
//读取字符串
reader.ReadString('分隔符')
时间
time包
//获取时间
now := time.Now()
//获取年月日
now.Yaer()
now.Month()
now.Day()
时间戳
now.Unix()
now.UnixNano()//纳秒
time.Unix(时间戳对象,0)//将时间戳转换为time对象
时间间隔
Duration类型代表时间间隔,小时、分钟、秒、微秒。
实践操作
now := time.Now()
now.Add(time.Hour)//增加一小时
now.Sub(time.Hour)//减少一小时
反射
并发
go 函数名()
如果main函数结束,那么启动的线程也会结束。
同步
var wg sync.WaitGroup
func main(){
wg.Add(1)//启动计数
wg.Done()//结束一个
wg.Wait()//等待所有goroutine都结束
}
GOMAXPROCS
//设置最大可同时执行线程数
runtime.GOMAXPROCS(数量)//默认cpu的逻辑核心数
channel
channle遵循先入先出。channel可以让一个goroutine发送值到另一个goroutine。
负责goroutine通信。
//声明指定元素类型 通道,channel类型需要初始化才能使用
var 变量 chan 元素类型
//初始化通道
make(chan 元素类型, [缓冲区大小])
//向通道发送值
通道名称 <- 值
//从通道接受值,需确定类型
x := <- 通道名称
<- 通道名称
//关闭通道
close(通道名称)
单向通道
只接受或只发送。
//只发送
chan<-
//只接受
<-chan
select多路复用
select会一直等待直到某个case被响应,再去执行对应语句.既能接受值也能发送值
如果多个case同时满足,select会随机一个。没有case的select会一直等待。
select{
case <-通道名称1:
...
case <-通道名称2:
...
case 通道名称 <- 值:
//发送通道处理
default:
默认
}
随机
//设置种子
rand.Seed(time.Now().UnixNano())//使用微秒作为种子
并发处理
互斥锁
//互斥锁
lock sync.Mutex
//加锁
lock.Lock()
//解锁
lock.Unlock()
//读写互斥锁
lock sync.RWMutex
//读锁
lock.RLock()
//解读锁
lock.RUnlock()
//写锁
lock.WLock()
//解写锁
lock.WUnlock()
sync.Once 只操作一次
sync.Map 保证map的并发安全。可替代map使用。
atomic原子性操作.
网络编程
TCP
1、监听端口
2、接受客户端请求建立连接
3、创建goroutine处理链接
使用net包
//监听
listen, err := net.Listen(协议,地址及端口)
//接受连接
listen.Accept()
//客户端发送
conn, err := net.Dial(协议, 地址及端口)
conn.Write()//发送数据