为了账号安全,请及时绑定邮箱和手机立即绑定

交换接口实现,无开销

交换接口实现,无开销

Go
胡说叔叔 2021-05-15 15:08:25
给定一个接口和两个(或更多)实现,在扩展功能时,我很难轻松地切换实现。例如,假设有一个接口INumber支持Inc和String以及两个实现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 // nopefunc (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?顺便说一句,真正的例子是一组整数和一个整数到整数的映射,这些整数具有数百万个实例,所有实例都交织在一起(而且不行,仅map [int] bool是不够的-太慢了,根据用例而定,bitset很有趣,依此类推。 ),并通过更改代码中的2-3行来轻松测试集合和映射的不同实现(理想情况下只是类型,并且可能是实例的通用创建或复制)任何帮助表示赞赏,我希望这还没有被要求...
查看完整描述

2 回答

?
杨魅力

TA贡献1811条经验 获得超6个赞

您使用嵌入的变体实际上并未嵌入。嵌入字段是匿名的,然后Go会自动委托。


这将您的示例简化为:


type EvenCounter3 struct {

    INumber

}


func (this *EvenCounter3) IncTwice() {

    this.Inc() // using this.n.Inc() twice makes it slower

    this.Inc()

}

请注意,String()是自动委派的(在Go语言中为“提升”)。


至于两次调用Inc()会使它变慢,那是使用接口的限制。接口的重点是不公开实现,因此您无法访问其内部数字变量。


查看完整回答
反对 回复 2021-05-31
?
森栏

TA贡献1810条经验 获得超5个赞

我不确定我是否正确理解您要达到的目标。也许是这样的?


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)

}

(在这里)


输出


44


查看完整回答
反对 回复 2021-05-31
  • 2 回答
  • 0 关注
  • 167 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信