new 和 make 对于引用类型的差异
例:map类型,new仅分配map类型本身所需内存,并未键值存储内存
具有相同声明的未命名类型被视作同一类型:
具有相同类型的指针
具有相同元素类型和长度的数组
具有相同元素类型的切片
具有相同键值类型的字典
具有相同数据类型及操作方向的通道
具有相同字段序列(字段名,字段类型,标签以及字段顺序)的结构体
具有相同签名(参数和返回值列表,不包括参数名)的函数
具有相同方法集(方法名,方法签名,不包括顺序)的接口
指针可执行相等运算,不可进行加减和类型转换
如果两个指针指向同一地址或者都为nil,则相等
if...else...
switch
无须显式执行break,如需贯通后续一个case,执行fallthrough
for...range...
支持字符串,数组,数组指针,切片,字典,通道
goto
不能跳转到其他函数,或内层代码块
break 和 continue 可在多层嵌套中配合标签指定目标层级
函数
无须前置声明
不支持命名嵌套定义
不支持同名函数重载
不支持默认参数
支持不定长变参
支持多返回值
支持命名返回值
支持匿名函数和闭包
函数只能判断是否为nil,不能进行其他判断
变参本质是切片,可以直接传递切片
闭包是函数和引用环境的组合体,容易造成变量逃逸到堆,谨慎使用
func test(x int) func() {
return func() {
println(x)
}
}
defer 常用于资源释放,解除锁定,以及错误处理等操作
recover 必须在延迟调用函数中执行才能正常工作
除非是不可恢复性,导致系统无法正常工作的错误,否则不建议使用panic
字符串string类型 支持!= == < > + +=
允许以索引号访问,但不能获取元素地址
数组初始化时第一维可使用[...],编译器会自行计算元素数量
如何选择方法的receiver的类型
- 要修改实例状态,用*T
- 无须修改状态的小对象或固定值,建议用T
- 大对象建议用*T,以减少复制成本
- 引用类型、字符串、函数等指针包装对象,直接用T
- 若包含Mutex等同步字段,用*T,避免因复制造成锁操作无效
- 其他无法确定的情况,都用*T
接口
- 不能有字段
- 不能定义自己的方法
- 只能声明方法,不能实现
- 可嵌入其他接口类型
对于嵌入其他接口,超集可隐式转换为子集,反过来则不行
并发
通常情况下,用多进程实现分布式和负载均衡,减轻单进程垃圾回收压力
用多线程抢夺更多的处理器资源
用协程来提高处理器时间片利用率
sync.WaitGroup 通过add、done和wait来实现多任务等待
goroutine 无法设置优先级,无法获取编号,没有局部存储,甚至连返回值都会被抛弃
gosched 暂停,释放当前线程并放回队列等待下次调度
很少用到gosched,因为运行时会主动向长时间运行(10ms)的任务发出抢占调度
goexit 立即终止当前任务,并确保所有已注册的延迟调用被执行
如果在main里面调用goexit,它会等待其他任务结束,然后让进程直接崩溃
os.exit 也可终止进程,但不会执行延迟调用
go 鼓励使用CSP通道,以通信来代替内存共享,实现并发安全
通道,底层实现是一个队列。同步模式下,发送方和接收方配对,直接复制数据给对方,如配对失败,则加入等待队列直到另一方出现被唤醒
异步模式下,发送方要求有空槽写入,接收方要求有数据可读,否则加入等待队列直到有数据被唤醒
cap 和 len 分别可返回异步通道缓冲区大小和已缓冲数量,对于同步通道,始终返回0
向已关闭通道发送数据,引发panic
从已关闭通道接收数据,返回已缓冲数据或零值
无论收发,nil通道都会阻塞
重复关闭或关闭nil通道都会引发panic
单向通道不可进行逆操作
close不能用于接收端
无法将单向通道重新转换回去
当所有case中的通道都不可用时,select会执行default,避免select阻塞
通道并非用来取代锁,通道倾向于解决逻辑层次的并发处理架构,而锁则用来保护局部范围内的数据安全
mutex作为匿名字段时,相关方法必须实现为 pointer-receiver,否则会因复制导致锁机制失效
对性能要求较高时,应避免使用defer unlock
读写并发时,用RWMutex性能会更好一些
对单个数据读写保护,可尝试用原子操作
执行严格测试,尽可能打开数据竞争检查
导入
import 别名 包
import "github.com/test/test" 默认方式 test.A
import x "github.com/test/test" 别名方式 x.A
import . "github.com/test/test" 简便方式 A
import _ "github.com/test/test" 初始化方式 无法引用,仅用来初始化目标包
简便方式常用于单元测试代码中,不推荐在正式项目代码中使用
初始化方式仅是为了让目标包的初始化函数得以执行,而非引用其他成员
go build/run/test 编译、运行和测试
包由一个或多个保存在同一个目录下(不包含子目录)的源文件组成
包名与目录名并无关系,不要求保持一致
包内每个源文件都可以定义一到多个初始化函数(init),但编译器不保证执行次序,且初始化函数无法被调用
内部包
所有保存在internal目录下的包(包括自身)仅能被其父目录下的包(含所有层次的子目录)访问
反射
reflect.TypeOf().Type() 代表真实类型(静态类型)
reflect.TypeOf().Kind() 代表基础结构类型(底层类型)
reflect.TypeOf().Elem() 返回指针、数组、切片、字典(值)、或通道的基类型
反射能探知当前包或外包的非导出结构成员(其实对于反射而言,都是外包)
网友评论