这是一个自Go1.0以来就存在的bug。请考虑以下包:
package iface // import "github.com/dsnet/example/iface1/iface"
import "fmt"
import "reflect"
func CheckInterface() {
type iface interface { unexported() }
var v interface{} = foo{}
t := reflect.TypeOf(v)
t1 := reflect.TypeOf((*iface)(nil)).Elem()
t2 := reflect.TypeOf((*interface { unexported() })(nil)).Elem()
fmt.Println("reflect implements named interface: ", t.Implements(t1))
fmt.Println("reflect implements interface literal:", t.Implements(t2))
_, ok1 := v.(iface)
_, ok2 := v.(interface { unexported() })
fmt.Println("type assertion on named interface: ", ok1)
fmt.Println("type assertion on interface literal: ", ok2)
fmt.Println()
}
type foo struct{}
func (foo) unexported() {}
package iface // import "github.com/dsnet/example/iface2/iface"
import "fmt"
import "reflect"
func CheckInterface() {
type iface interface { unexported() }
var v interface{} = foo{}
t := reflect.TypeOf(v)
t1 := reflect.TypeOf((*iface)(nil)).Elem()
t2 := reflect.TypeOf((*interface { unexported() })(nil)).Elem()
fmt.Println("reflect implements named interface: ", t.Implements(t1))
fmt.Println("reflect implements interface literal:", t.Implements(t2))
_, ok1 := v.(iface)
_, ok2 := v.(interface { unexported() })
fmt.Println("type assertion on named interface: ", ok1)
fmt.Println("type assertion on interface literal: ", ok2)
fmt.Println()
}
type foo struct{}
func (foo) unexported() {}
在设置中,我们有两个名为iface
的包,它们的源代码完全相同,但它们具有不同的绝对包路径。
运行以下程序:
package main
import (
iface1 "github.com/dsnet/example/iface1/iface"
iface2 "github.com/dsnet/example/iface2/iface"
)
func main() {
iface1.CheckInterface()
iface2.CheckInterface()
}
打印以下内容(在Go1.0到Go1.8之间):
reflect implements named interface: true
reflect implements interface literal: true
type assertion on named interface: true
type assertion on interface literal: true
reflect implements named interface: true
reflect implements interface literal: false
type assertion on named interface: true
type assertion on interface literal: false
Go1.9的输出略有不同,但仍然是错误的。
我们期望调用iface1.CheckInterface()
和iface2.CheckInterface()
会产生完全相同的结果。然而,我们看到的并非如此。在iface2
中,通过接口字面量对未导出字段进行类型Assert不再正常工作,但在iface1
中它按预期工作。
5条答案
按热度按时间rhfm7lfc1#
在
iface1.CheckInterface()
的末尾添加以下两行是没问题的:但是在
iface2.CheckInterface()
的末尾添加它们会导致运行时恐慌。这种恐慌有些奇怪,当它被触发时,
iface1.CheckInterface()
中打印的文本不会显示(转到 1.9 alpha 1)。6qqygrtg2#
问题是
interface { unexported() }
在不同包中描述时会显示不同的类型,因为unexported
是一个未导出的标识符。然而,我们为两者生成的运行时类型描述符都具有一个链接器符号type.interface { iface.unexported() }
。也就是说,它是包名限定的,而不是包路径限定的。它还被标记为 dupok,因此链接器无法检测到冲突。这里的修复方法是我们需要通过它们的包路径来限定这些方法名,而不仅仅是它们的包名。
fslejnso3#
这显然是不希望看到的,但我认为在发布周期的后期修复这个问题过于微妙。我们显然已经习惯了1.0版本中的这个问题,所以我认为可以再等一个版本再进行修复。
2wnc66cl4#
https://golang.org/cl/106175提到了这个问题:
cmd/compile: omit unnecessary interface method expression wrappers
oiopk7p55#
这个问题一直存在。显然我们应该修复它,但它也不是发布障碍。