给定以下结构Foo
以及处理多种类型的目标(Handle
可以是Read
,Write
等)。我知道当我们使用空接口时,我们会丢失编译时类型检查,但除此之外,每个接口的优缺点是什么?最后,实现这一目标的最惯用方法是什么?
package main
type Foo struct {
A int
B string
}
//Handle all types with switch
func (f *Foo) Handle(obj interface{}) {
switch obj := obj.(type) {
case int:
//do int stuff...
f.A + obj
case string:
//do string stuff...
f.B + obj
default:
panic("Unknown type")
}
}
//Handle each type individually
func (f *Foo) HandleInt(i int) {
//do int stuff...
f.A + i
}
func (f *Foo) HandleString(s string) {
//do string stuff...
f.B + s
}
答案 0 :(得分:2)
如果您要通过reflect
处理用户定义的类型,则必须使用空接口。那是fmt.Printf
,json.Encode
和binary.Write
接受它的理由。就您之前发布的Merkle tree scenario而言,如果您的Hash()
基于reflect
的回退,您可以使用空白界面。哈希用户创建的结构。
如果您只为几种关键类型([]byte
,string
提供方法,那么具体方法可能更有意义。除了编译时检查之外,函数列表还可以作为您可以散列的内容的文档。另一方面,如果你想要散列的十多种类型 - 想想所有(u)int类型和它们的切片 - 我想我会使用interface{}
只是为了一个整洁的API,除非你绝对需要最好的表现,但我不认为这样或那样明确的共识。
答案 1 :(得分:1)
一个很好的例子是package sort(sources here),其中:
如果您对Handle(obj interface{})
=>执行相同的操作Handle(obj Interface)
,这将帮助您使用“Interface
”中声明的方法定义一次(对于更复杂的类型)。
满足所述Interface
的任何类型都将传递给通用Handle()
函数
你也可以处理切片(类似于this example for sort
)或使用定义的集合。