我注意到函数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

try 取消引用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")
    }
}

请注意,在本例中,这不仅仅是为了及早检测错误,这也是一项要求,因为对于编译器来说,不能保证会达到返回语句.您也可以将panic("unreachable")语句移到switch之后(而不是default分支),这是一个品味问题.

如果您将上述函数更改为不返回,而是打印符号,那么让default分支处于panic 状态仍然是一种良好的做法,尽管这在本变体中不是必需的:

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")
    }
}

Go相关问答推荐

区分Terminal和Hook Zerolog Go中的错误级别日志(log)输出

如何将泛型函数作为参数传递给golang中的另一个函数?

为什么我不能使用Docker从本地访问我的Gin应用程序?

Golang Viper:如果第一个字段不存在,如何从另一个字段获取值

Hugo错误:没有为此项目配置现有内容目录

迭代字符串并用映射值替换原始字符串中的值的惯用方法

如何将 goose 迁移与 pgx 一起使用?

使用 httptest 对 http 请求进行单元测试重试

为什么 net/http 不遵守超过 30 秒的超时持续时间?

错误!在为 age-viewer-go 运行 wails dev 或 wails build 命令时

GitHub 中 REST API 的 aws 凭证问题

如何在 `hashicorp / terraform-exec` 中将 `ApplyConfig` 传递给 `tf.Apply()`?

Gorm 预加载给出了模糊的列错误

如何确定作为函数参数传递的指针是否正在被修改或副本是否正在被修改?

Golang计算 struct struct 中的字段数

每次有人进入我的网站时如何运行特定功能?

当有多个同名包时如何在vscode中显示golang包完整路径?

如何允许可转换为指针的泛型类型参数化另一种可转换为指针的泛型类型?

Gorilla/Mux 和 Websocket 竞赛条件,这安全吗?

为什么 Go 的构造函数要返回地址?