为什么将<nil>分配给Go中的接口类型是否有效?

 kcz1596369 发布于 2023-01-18 03:38

http://play.golang.org/p/_GP3RZTh4Q

package main

import "fmt"

type TesterInterface interface{
    Yell()
}

type Tester struct{}

func (t Tester) Yell() {
    fmt.Println("HELLO")
}

func main() {
    var t TesterInterface
    t = Tester{}
    t.Yell()
    t = nil
    t.Yell()
}

我希望编译器抱怨第19行(t = nil),因为nil没有实现Yell(),但程序运行并提供以下输出:

HELLO
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0xffffffff addr=0x0 pc=0x201a9]

goroutine 1 [running]:
runtime.panic(0xef060, 0x1b3d44)
    /tmp/sandbox/go/src/pkg/runtime/panic.c:266 +0xe0
runtime.panicstring(0x1b3d44, 0x1b85)
    /tmp/sandbox/go/src/pkg/runtime/panic.c:489 +0x120
runtime.sigpanic()
    /tmp/sandbox/go/src/pkg/runtime/os_nacl.c:254 +0x80
main.main()
    /tmpfs/gosandbox-229cdcdf_329829af_705be907_f12cf4dc_ed51e32e/prog.go:20 +0xa9
runtime.main()
    /tmp/sandbox/go/src/pkg/runtime/proc.c:220 +0x1c0
runtime.goexit()
    /tmp/sandbox/go/src/pkg/runtime/proc.c:1394

goroutine 2 [syscall]:
runtime.notetsleepg(0xfeefdf88, 0x0, 0xf8475800, 0xd)
    /tmp/sandbox/go/src/pkg/runtime/lock_sema.c:254 +0xa0
runtime.MHeap_Scavenger()
    /tmp/sandbox/go/src/pkg/runtime/mheap.c:463 +0xc0
runtime.goexit()
    /tmp/sandbox/go/src/pkg/runtime/proc.c:1394
created by runtime.main
    /tmp/sandbox/go/src/pkg/runtime/proc.c:179
 [process exited with non-zero status]

Program exited.

为什么编译器认为分配nil给接口是合法的?

另外,来自Go-docs:

接口类型的变量可以使用方法集存储任何类型的值,该方法集是接口的任何超集.

"nil"如何包含一个超集的方法集TesterInterface?文档接着说

接口类型的未初始化变量的值为nil.

但这似乎与第一个陈述相矛盾.

2 个回答
  • Go编程语言规范

    零值

    当分配内存来存储值时,无论是通过声明还是调用make或new,并且没有提供显式初始化,内存都会被赋予默认初始化.这种值的每个元素都设置为其类型的零值:布尔值为false,整数为0,浮点数为0.0,字符串为"",指针,函数,接口,切片,通道和映射为nil.

    该值nil对于接口类型变量有效,因为它是接口类型的零值.

    在围棋的数据结构:接口介绍了接口值的实现.

    2023-01-18 03:59 回答
  • 当你提出诸如"为什么编译器认为它合法......"这样的问题时总是很冒险.答案就像往常一样,因为那是语言,每个接口都接受这个nil值.但是还有更多的方面:接口的实现,以及如果不是这样,Go将如何工作.

    从后者开始,如果nil不是接口的合法值,请考虑问题.你会如何取代常见的习语:

    func Something() error {
        ...
        return nil
    }
    

    这取决于nil有效的事实error.类似地,指针满足接口是很常见的.如果nil还没有满足界面,你会如何返回nil指针?记住,nil这只是一个价值.

    对于实现,请参阅为什么我的nil错误值不等于nil?关键是接口由类型和值的元组组成,对于每个接口,元组(nil, nil)都是有效的.

    我假设你同意"typed nil"(即nil一些特定的指针类型)应该可以分配给由其指针类型实现的接口,对吗?因此必须将接口视为可能的接口nil,并且必须nil以与检查nil指针完全相同的方式检查接口.因此排除无类型的安全性没有任何好处nil,但是你可以打破许多有用的东西(比如返回"无错误").

    (这最后一部分有一点轻微的意思.再仔细阅读"为什么我的nil错误值不等于nil?"你会发现你不能轻易地检查一个包含nd值的接口.只能通过类型将接口断言为其底层指针类型或使用反射来实现.这并没有显着改变这一点,但我不想掩盖这个问题.)


    编辑

    根据@ newacct下面的评论,我们发现了一些无关紧要的观点.

    PeterSO的回答也非常重要.每种类型必须具有零值.接口的零值还有什么nil呢?

    2023-01-18 04:00 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有