语法相关
defer
defer的执行时机为归属的函数退出释放资源时执行,deferFunctionList是一个栈结构,先defer的最后执行。
func fileSize(filename string) int64{
f, err := os.Open(filename)
if err != nil {
return 0
}
defer f.Close()
info, err := f.Stat()
if err != nil {
// 触发defer
return 0
}
size := info.Size()
//触发defer
return size
}
context
// 普通context调用
ctx, cancel := context.WithCancel(context.Background())
// 带超时的context调用
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 5)
// 多个goroutine传值
ctx := context.WithValue(context.Background(), key, value)
- 普通context
```go
func run(ctx context.Context, id int) {
for{
} }select { case <-ctx.Done(): fmt.Printf("任务结束") return default: fmt.Printf("任务执行中") time.Sleep(time.Second * 2) }
func main(){ ctx, cancel := context.WithCancel(context.Background()) go run(ctx,1) go run(ctx,2) time.Sleep(time.Second * 10) cancel() return }
- 超时context
```go
func coroutine(ctx context.Context, duration timeDuration,id int, wg *sync.WaitGroup){
for {
select{
case <-ctx.Done():
fmt.Printf("协程退出")
wg.Done()
return
case <-time.After(duration):
fmt.Printf("消息来自协程")
}
}
}
func main(){
// WaitGroup等待所有的goroutine执行完毕,收到<-ctx.Done()中至信好后使wg中需要等待的goroutine数量减1
wg:= &sync.WaitGroup{}
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 5)
defer cancel()
for i:=0;i<3;i++{
wg.Add(1)
go coroutine(ctx, 1 *time.Second, i, wg)
}
}
指针
*p++ //只增加p指向的变量的值,不改变p指针
*p = 4 // 实现间接赋值
只执行一次
type Singleton struct {
}
var singleInstance *Singleton
var once sync.Once
func GetSingletonObj() *Singleton{
once.Do(func(){
fmt.Println("Create Obj")
singleInstance = new(Singleton)
})
return singleInstance
}
func TestGetSingleObj(t *testing.T){
var wg sync.WaitGroup
for i:=0;i<10;i++{
wg.Add(1)
go func(){
obj := GetSingletonObj()
wg.Done()
}()
wg.Wait()
}
}
对象池
type ReusableObj struct{
}
type ObjPool struct{
bufChan chan *ReusableObj
}
// 初始化缓冲池
func InitObjPool(numOfObj int) *ObjPool {
objPool := ObjPool{}
objPool.bufChan = make(chan *ReleaseObj, numOfObj)
for i:0; i<numOfObj;i++{
objPool.bufChan <- &ReusableObj{}
}
return &objPool
}
// 获取对象
func (pool *ObjPool) GetObj(timeout time.Duration)(*ReleaseObj, err){
select{
case ret := <- pool.bufChan:
return ret, nil
case <- time.After(timeout):
return nil, errors.New('timeout')
}
}
func (p *ObjPool) ReleaseObj(obj *ReusableObj) error{
select{
case p.bufChan <- obj:
return nil
default:
return errors.New('overflow')
}
}
func TestObjPool(t *testing.T){
pool := InitObjPool(10)
for i:=0;i<11;i++{
if v, err pool.GetObj(time.Second * 1); err != nil{
t.Error(err)
}else{
if err := pool.ReleaseObj(v); err != nil{
t.Error(err)
}
}
}
}
类型断言
PrimaryExpression.(Type)
v, ok = a.(T)
// ok必须得有,否则断言失败会panic
错误处理
- 不相信外部输入
- 先进行异常处理
var (
ErrInvalidUnreadByte = errors.New("bufio: invalid use of UnreadByte")
ErrInvalidUnreadRune = errors.New("bufio: invalid use of UnreadRune")
ErrBufferFull = errors.New("bufio: buffer full")
ErrNegativeCount = errors.New("bufio: negative count")
)
data, err := b.Peek(1)
if err != nil {
switch err {
case bufio.ErrNegativeCount:
// ... ...
return
case bufio.ErrBufferFull:
// ... ...
return
case bufio.ErrInvalidUnreadByte:
// ... ...
return
default:
// ... ...
return
}
}
// 使用errors.Is
if errors.Is(err, ErrOutOfBounds) {
// 越界的错误处理
}
channel
对同一个无缓冲 channel,只有对它进行接收操作的 Goroutine 和对它进行发送操作的 Goroutine 都存在的情况下,通信才能得以进行,否则单方面的操作会让对应的 Goroutine 陷入挂起状态。对无缓冲 channel 类型的发送与接收操作,一定要放在两个不同的 Goroutine 中进行,否则会导致 deadlock。
- 无缓冲 channel 用作信号传递的时候,有两种情况,分别是 1 对 1 通知信号和 1 对 n 通知信号。我们先来分析下 1 对 1 通知信号这种情况。 ```go
type signal struct{}
func worker() { println(“worker is working…”) time.Sleep(1 * time.Second) }
func spawn(f func()) <-chan signal { c := make(chan signal) go func() { println(“worker start to work…”) f() c <- signal{} }() return c }
func main() { println(“start a worker…”) c := spawn(worker) <-c fmt.Println(“worker work done!”) } ```