2014-08-30 36 views
1

鉴于以下结构Foo和处理多种类型的目标(其中Handle可能是Read,Write等)。我明白,当我们使用空的界面时,我们会失去编译时类型检查,但除此之外,每个类型的优缺点是什么?最后,实现这个目标的最习惯的方式是什么?一种功能开启的类型vs许多类型的功能

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 
} 

回答

2

如果您要通过reflect处理用户定义的类型,则需要空接口。这是fmt.Printf,json.Encodebinary.Write接受它的理由。根据你之前发布的Merkle tree scenario,你在散列的东西,如果你的Hash()有一个基于reflect的回退来散列用户创建的结构,你会使用一个空的接口。

如果您只打算为几种关键类型提供方法([]byte,string,无论什么),具体方法可能更有意义。除了编译时检查外,函数列表还可以作为您可以散列的文档。另一方面,如果有像你想要散列的十几种类型 - 考虑所有(u)int类型和它们的片段 - 我想我会使用interface{}只是为了整洁的API,除非你绝对需要最好的表现,但我认为这种或那种方式没有明确的共识。

+0

是的,[u] int类型的数量实际上让我感到困扰。我并不期待每个内置类型都有一个方法。美学上,我宁愿有一种方法并记录下来。此外,可能包括3种特定方法和1种通用方法(两种方法)都会混淆用户。 – jpillora 2014-08-30 07:14:11

1

一个很好的例子是package sortsources here),其中:

  • 确实实现了基本类型的一种方法(如你的第二个方法)
  • 提出了一种interface的类型被排序必须执行。
  • 可以使用声明的方法。如果你Handle(obj interface{}) =>Handle(obj Interface)做同样的排序切片和用户定义的集合

,这将帮助你处理(用于更复杂的类型)定义一次,“ Interface'。
满足所述Interface的任何类型将被传递给通用Handle()函数。
而且您可以处理切片(类似于this example for sort)或使用定义的集合。

+0

感谢您的例子 - 这是一个很好的模式,但我希望能够处理内置类型(所有类型的[u]整数),所以我想我会用@ twotwotwo的答案。 – jpillora 2014-08-30 07:15:39