不可能的接口 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?。