Post

Go Programing

Go Programing

Go Programing Skills

接口型函数

example

1
2
3
4
5
6
7
8
9
// net/http 标准库
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}
type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
	f(w, r)
}

使用

  • 一个函数类型, 实现了一个接口的方法, 并在该方法中调用自身
  • 好处在于既可以将普通函数类型(通过类型转换)作为参数, 可以将结构体作为参数

import <相对路径>

  • 在go.mod文件中添加声明
    • require <package> v0.0.0
    • replace <package> => ./<package>

反射

  • 反射就是在程序运行时, 可以访问自身结构并且做出修改的一种能力
  • go反射中, 都是通过将interface{}转换为Type或者Value类型, 然后通过对Type和Value的操作, 来实现相应的功能
    • reflect.TypeOf(any)
    • reflect.ValueOf(any)

time.After

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// example
func doBadthing(done chan bool) {
  time.Sleep(time.Second)
  done <- true
}

func timeout(f func(chan bool)) error {
  done := make(chan bool)
  go f(done)
  select {
  case <-done: // func完成
    fmt.Println("done")
    return nil
  case <-time.After(time.Millisecond): // 启动异步定时器, 超时返回channel
    return fmt.Errorf("timeout")
  }
}

潜在问题

  • 当发生超时的时候, done没有接收者, 导致goroutine阻塞, 没法正常退出
    • 避免方式
      1. channel设置缓冲大小 e.g. done:=make(chan bool, 1)
      2. 不设置缓冲大小, 而是改用select尝试向done发送信号
        • 由done<-true改为select{case done<-true: default: return}
        • 当向done发送失败时(此时没有接收者), 走default就退出了
        • 这种方式还利于分段检测超时的情况(例如只检测第一段是否超时, 无超时, 后续任务继续执行)

context

  • context可以用来在复杂的情况下并发控制(如控制多个子goroutine, 或者子goroutine又开启了新的goroutine)
  • 功能:
    • 通知子协程退出(正常退出(context.WithCancel), 超时退出(context.WithTimeout)等)
    • 传递必要的参数 (context.WithValue)
This post is licensed under CC BY 4.0 by the author.