CodeQL 文档

不可能的接口 nil 检查

ID: go/impossible-interface-nil-check
Kind: problem
Security severity: 
Severity: warning
Precision: high
Tags:
   - correctness
Query suites:
   - go-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

Go 中的接口值是类型标记的,也就是说,它们本质上是 (value, type) 形式的键值对,其中 value 是具有给定 type 的非接口值。即使 valuenil,这样的键值对也永远不会是 nil

特别是,如果将非接口值 v 分配给类型为接口的变量 x,则无论 v 是什么,x 都不会是 nil。将 xnil 进行比较毫无意义,并且可能表示对 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)
	}
}

参考

  • ©GitHub, Inc.
  • 条款
  • 隐私