インタフェース{}が与えられた関数を実装しているかどうかを効率的にテストしようとしています。私の解決策は、この関数だけでインタフェースを作成し、インタフェース{}がこの単一関数インタフェースを実装しているかどうかを調べることです。ここでの2つのオプションは、リフレクションまたはタイプアサーションのどちらかを使用しているようです。どちらも同じ動作をしているようですが、速度には大きな違いがあります。なぜType.Implements()は型アサーションよりもはるかに遅いですか?
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
Implements()がキャッシュしない理由はありますか?これは、何かがインターフェイスを実装するかどうかが変わる可能性があることを期待していることを示唆しています(ただし、これが真の場合は、型アサーションキャッシングは間違いでしょうか?) – bradleyjkemp
なぜなら、 – Volker
@bradleyjkemp、「コンピューティング・ザ・イテーブル」のセクション[こちら](https://research.swtch.com/interfaces)を参照することをお勧めします。私の推測では、あなたのコメントには、タイプアサーション/スイッチがあり、具体的な型の値をインタフェース型の変数に代入しても、その型の新しいitableを実行時に計算する必要があるかもしれないが、コンパイラは有限実行可能なときにGoプログラムがそれ自体を変更することはできないからです... – kostix