3 回答
TA贡献1798条经验 获得超3个赞
这个问题很老,有一些很好的答案,但没有一个提出可以做到这一点的可能性。
在提出解决方案之前:我认为确保实现不会因为无法设置嵌入式接口字段而恐慌不是你的工作。有人可以传递一个实现,该实现显式定义了panic()显式调用的方法 。您无法检测到这种情况,但是,该实现不会比nil嵌入式接口字段更好。
好的,那么如何判断一个方法是否不能被调用,因为它会因为嵌入的接口字段而导致实现不可用而导致恐慌nil?
你说你不能/不想调用该方法并从恐慌中恢复,因为如果该方法可用,这将调用它并产生副作用。
事实是我们不必调用它。我们可以通过实例(而不是类型)来引用方法,然后必须解析实际的接收者。当然,如果接收者是嵌入式接口的动态值,如果该接口是nil,解析将导致运行时恐慌,但即使嵌入式接口不是 ,该方法也不会被调用nil。请注意,这实际上是一个Method value,并且获得一个 method value 会评估并保存接收者。这种接收器评估将失败。
让我们看一个例子:
type A interface {
Foo() string
}
type B struct {
A
}
func (b B) Int() int {
fmt.Println("B.Int() called")
return 0
}
func main() {
b := B{}
_ = b.Int
fmt.Println("We got this far, b.Int is realized")
}
这个程序会输出什么?只有"We got this far, b.Int is realized"。因为Int()方法是为B类型显式定义的,所以b.Int可以解析。并且因为它没有被调用,所以"B.Int() called"不会被打印。
如果我们这样做会怎样:
_ = b.Foo
由于Foo是来自B.A嵌入式接口的提升方法,并且b.A是nil,因此解析b.Foo将在运行时失败,并产生运行时错误,如下所示:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x47d382]
goroutine 1 [running]:
main.main()
/tmp/sandbox877757882/prog.go:24 +0x2
但我们可以从中恢复:
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered:", r)
fmt.Println("This means b.Foo is not realized!")
}
}()
_ = b.Foo
这将输出:
Recovered: runtime error: invalid memory address or nil pointer dereference
This means b.Foo is not realized!
试试Go Playground上的例子。
- 3 回答
- 0 关注
- 166 浏览
添加回答
举报