我试图有效地测试接口{}是否实现了给定的函数,我的解决方案是创建一个只有这个函数的接口,然后检查接口{}是否实现了这个单一的函数接口。这里的两个选项似乎是使用反射或类型断言。两者似乎都有相同的行为,但速度差异很大。
查看Value.Implements()的代码,它对值上定义的函数进行线性扫描,并将它们与接口进行比较。 然而,类型断言似乎只进行了一个恒定的时间比较(与接口中的函数数量无关)。
有没有理由为什么Implements()不会做一个类型断言?
基准:
package benchmarks
import (
"reflect"
"testing"
)
type ITest interface {
Foo()
}
type Base struct{}
func (Base) A() {}
func (Base) B() {}
func (Base) C() {}
func (Base) D() {}
func (Base) E() {}
func (Base) F() {}
func (Base) G() {}
func (Base) H() {}
func (Base) I() {}
func (Base) J() {}
var Interface = reflect.TypeOf((*ITest)(nil)).Elem()
func BenchmarkReflection(b *testing.B) {
var iface interface{}
iface = Base{}
for i := 0; i < b.N; i++ {
if reflect.TypeOf(iface).Implements(Interface) {
b.FailNow()
}
}
}
func BenchmarkAssertion(b *testing.B) {
var iface interface{}
iface = Base{}
for i := 0; i < b.N; i++ {
if _, ok := iface.(ITest); ok {
b.FailNow()
}
}
}
结果:
go test -run=XXX -bench=. so_test.go
goos: linux
goarch: amd64
BenchmarkReflection-8 10000000 208 ns/op
BenchmarkAssertion-8 200000000 9.24 ns/op
PASS
ok command-line-arguments 5.115s
答案 0 :(得分:8)
Go中的类型断言依赖于一个名为How do I disable Laravel view cache?的函数。如果您查看代码,您会发现它依赖于getitab
,additab
依赖于additab
(在同一文件中)。
现在,检查给定类型是否在Implements
内实现接口的实际逻辑与reflect
中的// both inter and typ have method sorted by name,
// and interface names are unique,
// so can iterate over both in lock step;
// the loop is O(ni+nt) not O(ni*nt).
完全相同 - 线性搜索,甚至指出在这个评论中:
additab
然而,区别在于df[grep("TissueA", names(df)] # Extract
sum(grepl("TissueA", names(df)) # Count
实际上利用了缓存 - 类型断言的结果存储在哈希映射中,因此相同类型的后续类型断言将在恒定时间内运行,这就是为什么你'重新看到性能上的巨大差异。