问题描述
我注意到函数throw
中有一行*(*int)(nil) = 0
//go:nosplit
func throw(s string) {
// Everything throw does should be recursively nosplit so it
// can be called even when it's unsafe to grow the stack.
systemstack(func() {
print("Fatal error: ",s,"\n")
})
gp := getg()
if gp.m.throwing == 0 {
gp.m.throwing = 1
}
fatalthrow()
*(*int)(nil) = 0 // not reached
}
*(*int)(nil) = 0
是什么意思?并且由于无法到达此行*(*int)(nil) = 0
,为什么在这里?有什么特殊用途吗?
解决方法
该行:
*(*int)(nil) = 0
尝试取消引用nil
指针并为其分配值,这始终是运行时的恐慌。该代码永远都不会到达此行,但是如果仍然会发生(例如,将来发生错误的代码更改),则会恐慌,因此可以检测到该错误,并且不会被忽略。
在代码中也执行类似的操作是常识,但是带有更明显的“构造”,例如panic("unreachable")
。例如:
func sign(a int) string {
switch {
case a > 0:
return "Positive"
case a < 0:
return "Negative"
case a == 0:
return "Zero"
default:
panic("unreachable")
}
}
请注意,在此示例中,这不仅是要及早发现错误,而且这也是一个要求,因为对于编译器,无法保证将返回return语句。您也可以将panic("unreachable")
语句移到switch
之后(而不是default
分支),这是一个问题。
如果您将上述函数更改为不返回而是打印符号,则将default
分支置于紧急状态仍然是一个好习惯,尽管在此变体中这不是必需的:
func printSign(a int) {
switch {
case a > 0:
fmt.Println("Positive")
case a < 0:
fmt.Println("Negative")
case a == 0:
fmt.Println("Zero")
default:
panic("unreachable")
}
}