不可能的接口 nil 检查¶
ID: go/impossible-interface-nil-check
Kind: problem
Security severity:
Severity: warning
Precision: high
Tags:
- correctness
Query suites:
- go-security-and-quality.qls
Go 中的接口值是类型标记的,也就是说,它们本质上是 (value, type) 形式的键值对,其中 value 是具有给定 type 的非接口值。即使 value 为 nil,这样的键值对也永远不会是 nil。
特别是,如果将非接口值 v 分配给类型为接口的变量 x,则无论 v 是什么,x 都不会是 nil。将 x 与 nil 进行比较毫无意义,并且可能表示对 Go 接口值的误解或其他一些潜在的错误。
建议¶
仔细检查比较,以确保它不是错误的征兆。
示例¶
以下示例显示了函数 fetch 的声明,该函数获取 URL 的内容,返回内容或错误值,该错误值是指向自定义错误类型 RequestError 的指针(未显示)。函数 niceFetch 包装了此函数,打印出 URL 内容或错误消息。
package main
import "fmt"
func fetch(url string) (string, *RequestError)
func niceFetch(url string) {
var s string
var e error
s, e = fetch(url)
if e != nil {
fmt.Printf("Unable to fetch URL: %v\n", e)
} else {
fmt.Printf("URL contents: %s\n", s)
}
}
但是,由于 e 被声明为 error 类型,这是一个接口,因此 nil 检查永远不会成功,因为 e 永远不可能是 nil。
在这种情况下,可以使用运算符 := 的简短变量声明来解决问题,该声明将自动为 e 推断更精确的非接口类型 *ResourceError,从而使 nil 检查按预期运行。
package main
import "fmt"
func niceFetchGood(url string) {
s, e := fetch(url)
if e != nil {
fmt.Printf("Unable to fetch URL: %v\n", e)
} else {
fmt.Printf("URL contents: %s\n", s)
}
}
参考¶
Jordan Orelli:如何在 Go 中使用接口。
Go 常见问题解答:为什么我的 nil 错误值不等于 nil?。