给定一个接口和两个(或更多)实现,我在扩展功能时很难轻松切换实现。
例如,假设存在支持Inc和String的接口INumber以及具有明显实现的两个实现NumberInt32和NumberInt64。假设我想在INumber之上实现EvenCounter。 EvenCounter只有一个IncTwice并且应该拨打Inc两次。我很难在不使用EvenCounter中围绕INumber的额外结构的情况下获得正确的类型。
type INumber interface {
Inc()
String() string
}
type NumberInt32 struct {
number int32
}
func NewNumberInt32() INumber {
ret := new(NumberInt32)
ret.number = 0
return ret
}
func (this *NumberInt32) Inc() {
this.number += 1
}
func (this *NumberInt32) String() string {
return fmt.Sprintf("%d", this.number)
}
// type NumberInt64.... // obvious
这是我奋斗的地方
type EvenCounter1 INumber // nope, additional methods not possible
type EvenCounter2 NumberInt32 // nope
func (this *EvenCounter2) IncTwice() {
for i:=0; i < 2; i+=1 {
// this.Inc() // Inc not found
// INumber(*this).Inc() // cannot convert
// in, ok := *this.(INumber) // cannot convert
// v, ok := this.(INumber) // cannot convert
// a concrete conversion a) does not work and b) won't help
// here it should be generic
// v, ok := this.(NumberInt32)
// How do I call Inc here on this?
}
}
只需嵌入结构中......
type EvenCounter3 struct {
n INumber
}
func (this *EvenCounter3) IncTwice() {
n := this.n // that is a step I want to avoid
n.Inc() // using this.n.Inc() twice makes it slower
n.Inc()
}
func (this *EvenCounter3) String() string {
return this.n.String()
}
我可以满足为每种方法手动实现委派的需要,但是 显然我想依靠INumber而不是具体的实现(那个 将意味着改变很多地方尝试另一种实现,但是,我想避免额外的间接和(最有可能?)额外的空间。有没有 避免结构的方法,并直接说EvenCounter是一个(特定的)INumber与其他方法?
BTW真正的例子是一组整数和一个整数映射到整数,数百万个实例都交织在一起(不,只是map [int] bool赢得不够 - 太慢了,bitset很有趣依赖于用例等)并通过更改代码中的2-3行来轻松测试集合和映射的不同实现(理想情况下只是类型和可能 实例的通用创建。制作副本)任何帮助表示赞赏,我希望现在还没有得到帮助......
答案 0 :(得分:4)
使用嵌入的变体实际上并没有嵌入。 Embedded fields are anonymous and Go then delegates automatically
这将您的示例简化为:
type EvenCounter3 struct {
INumber
}
func (this *EvenCounter3) IncTwice() {
this.Inc() // using this.n.Inc() twice makes it slower
this.Inc()
}
请注意,String()会自动委派(&#34;提升&#34;在Go中)。
至于调用Inc()两次使它变慢,那么,这是使用接口的限制。接口的要点是不公开实现,因此您无法访问其内部数字变量。
答案 1 :(得分:0)
我不确定我是否正确理解你想要实现的目标。也许是这样的?
package main
import "fmt"
type Num interface {
Inc()
String() string
}
type Int32 struct {
int32
}
func (n *Int32) Inc() {
(*n).int32++
}
func (n Int32) String() string {
return fmt.Sprintf("%d", n.int32)
}
type EventCounter interface {
Num
IncTwice()
}
type Event struct {
Num
}
func (e Event) IncTwice() {
e.Inc()
e.Inc()
}
func main() {
e := Event{&Int32{42}}
e.IncTwice()
fmt.Println(e)
}
(Alse here)
输出
44