GO·NOTE

一份 Go 开发工程师的学习笔记

0%

f.Close() 返回的 error 用处理吗?

疑问

代码中的 f.Close() 返回的 error 用处理吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"log"
"os"
)

func main() {
f, err := os.Create("test.txt")
defer f.Close() // 忽略 error.
if err != nil {
log.Fatal(err)
}
f.WriteString("hello world")
}

解答

close() 是一个系统调用, 它出错的情况只有:

1
2
3
4
5
6
ERRORS
The close() system call will fail if:
[EBADF] fildes is not a valid, active file descriptor.
[EINTR] Its execution was interrupted by a signal.
[EIO] A previously-uncommitted write(2) encountered an input/output
error.

程序中经常遇到的是 EIO, 也就是在在 close 之前, read/write 已经报错了(比如文件 fd 已经提前关闭, 网络的话 TCP 连接已经断开等),
这种情况忽略 close 的 err 才是正确的逻辑.

因为调用 close 的核心目的是释放资源, 而不管在这次调用之前资源是否已经被释放了, 程序只保证在该次调用 close 后资源一定是已经释放的状态即可.

而且在官方库中,也没有对返回的 error 进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
func (t *tester) packageHasBenchmarks(pkg string) bool {
pkgDir := filepath.Join(goroot, "src", pkg)
d, err := os.Open(pkgDir)
if err != nil {
return true // conservatively
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
return true // conservatively
}
for _, name := range names {
if !strings.HasSuffix(name, "_test.go") {
continue
}
slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
if err != nil {
return true // conservatively
}
if bytes.Contains(slurp, funcBenchmark) {
return true
}
}
return false
}