2016-08-23 9 views
0
package main 

import "fmt" 

type Pet interface { 
    Bark() 
} 

type Dog int 

func (d Dog) Bark() { 
    fmt.Println("W! W! W!") 
} 

type Cat int 

func (c Cat) Bark() { 
    fmt.Println("M! M! M!") 
} 

type AdoptFunc func(pet Pet) 

func adoptDog(dog Dog) { 
    fmt.Println("You live in my house from now on!") 
} 
func adoptCat(cat Cat) { 
    fmt.Println("You live in my house from now on!") 
} 

func main() { 
    var adoptFuncs map[string]AdoptFunc 
    adoptFuncs["dog"] = adoptDog // cannot use adoptDog (type func(Dog)) as type AdoptFunc in assignment 
    adoptFuncs["cat"] = adoptCat // the same as above 
} 

上記のコードと同様に、マップや配列を使用して同様の関数adoptXxxを収集する方法はありますか?そうでない場合、この状況に使用する正しいパターンは何ですか?類似の関数のグループを総称的に表す方法はありますか?

+1

メイク 'adoptCat'は' Cat'の代わりに 'Pet'を受け入れます。一般的には、継承と古典的なOOPを忘れて再設計する。 IMHOのペット、猫、犬は悪い例です。 – Volker

答えて

2

マップを関数コレクションとして使用するには、関数のシグネチャを一致させるように変更する必要があります。 func(Pet)は、func(Dog)と同じ種類ではありません。

あなたはPetに取ると、正しいペットが入力されていることを確認するために選択タイプを行うにはAdoptXXX関数を再書き込むことができます。

func adoptDog(pet Pet) { 
    if _, ok := pet.(Dog); !ok { 
     // process incorrect pet type 
    } 
    fmt.Println("You live in my house from now on!") 
} 
+0

ペットから犬への変換は簡単です。たとえば、同等のものがバイトスライスをProtoBufferメッセージにアンマーシャリングしている場合、私はOnXxxMessageのようなすべての関数でそれを行う必要がありますか? – lfree

+0

protobufメッセージは単純に一連のバイトであるため、非整列化は型変換ではありません。非整列化関数はこのシーケンスを読み取り、別のデータ構造体にそのシーケンスを設定します。インタフェースは、予想される動作を定義するために使用されます。型がインタフェースを実装している場合、それはそのインタフェースの振る舞いを持ちます。つまり、複数のコンクリート型が同じ動作を示すことができる場合(異なる実装でも構いませんが)、型を保持するインターフェイスを使用し、必要に応じてメソッドを呼び出す必要があります。 – abhink

+0

あなたの特定の例では、 'OnXxxMessage'関数はメッセージを受け取り、メッセージを受信する各ペットにそれを渡します。つまり、 'OnXxxMessage'は、' ProcessMessage() 'メソッドのようなものをインターフェイスに提供する限り、' Pet'インターフェイスで直接動作することができます。 – abhink

関連する問題