4

インターフェイスと 2 つ (またはそれ以上) の実装がある場合、機能を拡張するときに実装を簡単に切り替えるのに苦労します。

たとえば、Inc と String をサポートするインターフェイス INumber と、明らかな実装を持つ NumberInt32 と NumberInt64 の 2 つの実装があるとします。INumber の上に EvenCounter を実装したいとします。EvenCounter には IncTwice しかなく、Inc を 2 回呼び出す必要があります。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であると直接言う方法はありますか?

ところで、実際の例は、整数のセットと、整数から整数へのマップであり、数百万のインスタンスがすべて絡み合っています(いいえ、map [int] boolだけでは不十分です-遅すぎる、ビットセットはユースケースなどに応じて興味深い. ) コード内の 2 ~ 3 行を変更することで、セットとマップのさまざまな実装を簡単にテストできます (理想的には型だけで、場合によってはインスタンスの一般的な作成とコピーの作成)。

助けていただければ幸いです。これがまだ尋ねられていないことを願っています...

4

2 に答える 2

4

埋め込みを使用するバリアントは、実際には埋め込みません。埋め込みフィールドは匿名であり、Go は自動的に委任します

これにより、例が次のように単純化されます。

type EvenCounter3 struct {
    INumber
}

func (this *EvenCounter3) IncTwice() {
    this.Inc() // using this.n.Inc() twice makes it slower
    this.Inc()
}

String() は自動的に委譲されることに注意してください (Go では「昇格」)。

Inc() を 2 回呼び出すと速度が低下しますが、これはインターフェイスを使用する際の制限です。インターフェイスのポイントは、実装を公開しないことです。そのため、内部の数値変数にアクセスできません。

于 2013-02-14T07:22:52.027 に答える
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)
}

こちらも


出力

44
于 2013-02-14T07:22:12.760 に答える