ioutil.go
这个包平时就用得很多了,就那几个函数,很简单的实现。值得一说的是 readAll
函数中的几行
// src/io/ioutil/ioutil.go ---- line 16
// readAll reads from r until an error or EOF and returns the data it read
// from the internal buffer allocated with a specified capacity.
func readAll(r io.Reader, capacity int64) (b []byte, err error) {
var buf bytes.Buffer
// If the buffer overflows, we will get bytes.ErrTooLarge.
// Return that as an error. Any other panic remains.
defer func() {
e := recover()
if e == nil {
return
}
if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge {
err = panicErr
} else {
panic(e)
}
}()
if int64(int(capacity)) == capacity {
buf.Grow(int(capacity))
}
_, err = buf.ReadFrom(r)
return buf.Bytes(), err
}
注意上面代码块的第 19 到 21 行,对 capacity
的判断,个人理解是因为后续要把 int(capacity)
传给 buf.Grow
函数,而在 buf.Grow
函数中如果参数小于零是会 panic
的,所以这里是在检测 int64
的 capacity
是否对 int32
有溢出,是否在转换成 int
后会变成负数,如果不会出现溢出再传给 buf.Grow
以确保安全
tempfile.go
这个文件就很酷了,写了两年 Go 的我居然现在才发现。这个文件提供了一些用于创建临时文件或临时目录的函数,当然这个所谓的临时文件不是说程序结束就给删掉了,而是名字随机化以免和其他文件冲突,用于不重要地缓存一些内容,随时可删除的那种,就像 /tmp/ 中的文件。
至于写了两年居然都没遇到这种需求?不不,我有这种需求的时候都是自己实现的,没想过原来标准库就提供了这种功能。
具体的实现,值得一说的也就一个随机数生成,但是不想看,记住它真的很随机生成的文件名不会重复就行了
// src/io/ioutil/tempfile.go ---- line 27
func nextRandom() string {
randmu.Lock()
r := rand
if r == 0 {
r = reseed()
}
r = r*1664525 + 1013904223 // constants from Numerical Recipes
rand = r
randmu.Unlock()
return strconv.Itoa(int(1e9 + r%1e9))[1:]
}
还出现了几个 Magic Number 就更没有深挖的欲望了。