ioutil.go

这个包平时就用得很多了,就那几个函数,很简单的实现。值得一说的是 readAll 函数中的几行

  1. // src/io/ioutil/ioutil.go ---- line 16
  2. // readAll reads from r until an error or EOF and returns the data it read
  3. // from the internal buffer allocated with a specified capacity.
  4. func readAll(r io.Reader, capacity int64) (b []byte, err error) {
  5. var buf bytes.Buffer
  6. // If the buffer overflows, we will get bytes.ErrTooLarge.
  7. // Return that as an error. Any other panic remains.
  8. defer func() {
  9. e := recover()
  10. if e == nil {
  11. return
  12. }
  13. if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
  14. err = panicErr
  15. } else {
  16. panic(e)
  17. }
  18. }()
  19. if int64(int(capacity)) == capacity {
  20. buf.Grow(int(capacity))
  21. }
  22. _, err = buf.ReadFrom(r)
  23. return buf.Bytes(), err
  24. }

注意上面代码块的第 19 到 21 行,对 capacity 的判断,个人理解是因为后续要把 int(capacity) 传给 buf.Grow 函数,而在 buf.Grow 函数中如果参数小于零是会 panic 的,所以这里是在检测 int64capacity 是否对 int32 有溢出,是否在转换成 int 后会变成负数,如果不会出现溢出再传给 buf.Grow 以确保安全

tempfile.go

这个文件就很酷了,写了两年 Go 的我居然现在才发现。这个文件提供了一些用于创建临时文件或临时目录的函数,当然这个所谓的临时文件不是说程序结束就给删掉了,而是名字随机化以免和其他文件冲突,用于不重要地缓存一些内容,随时可删除的那种,就像 /tmp/ 中的文件。


至于写了两年居然都没遇到这种需求?不不,我有这种需求的时候都是自己实现的,没想过原来标准库就提供了这种功能。


具体的实现,值得一说的也就一个随机数生成,但是不想看,记住它真的很随机生成的文件名不会重复就行了

  1. // src/io/ioutil/tempfile.go ---- line 27
  2. func nextRandom() string {
  3. randmu.Lock()
  4. r := rand
  5. if r == 0 {
  6. r = reseed()
  7. }
  8. r = r*1664525 + 1013904223 // constants from Numerical Recipes
  9. rand = r
  10. randmu.Unlock()
  11. return strconv.Itoa(int(1e9 + r%1e9))[1:]
  12. }

还出现了几个 Magic Number 就更没有深挖的欲望了。