2016-04-22 10 views
4

私は、ストレージAからフェッチして対応するタイプのストレージBに変換して格納する2つのストレージの中間層を作ろうとしています。私が変換する必要がある約50-100タイプがあるので、map[string]funcを使用し、storageA.Typeに基づいて、どの変換機能を呼び出す必要があるかを判断しました。インタフェースタイプのインタフェースを返す(別の)インタフェースタイプの構造体

これらの変換関数はそれぞれ、異なる構造体を返します。これらの構造体はすべて、ストレージBのさまざまな型を反映します。これらのストレージB構造体のそれぞれは共通のインタフェースを実装しているため、関数を呼び出すことができます。私の問題煮詰め

StorageBtype1インターフェイスStorageBTypeを実装していても、私はfunc(StorageAType) StorageBType1func(StorageAType) StorageBTypeにキャストすることができないということです。

単語の問題を説明するのが難しいと私は理解しているので、これはむしろ長くplaygroundを作成しました。 38行目から41行目と60行目から63行目をコメントアウトすると、実行されますが、使いたい行です。申し訳ありませんが、私はそれほど冗長ではっきりとした例を理解できませんでした。

回答にコメントする担当者がいないと思うので、私は私のstackoverflowアカウントを再作成しなければならなかったことに注意してください。

*編集:

非常に典型的です。ちょうど私がそれを解決する方法を実現することを頼んだ直後。正確な型の代わりにコンバータ関数のインタフェース型を返すことによって、この変更はplaygroundになりました。

答えて

2

異なる結果の型を持つ関数型は異なる型ですが、結果の型のいずれかが他の型を実装するかどうかは関係ありません。 Spec: Function types:

関数型は同じパラメータと結果種類持つ全ての機能の集合を表します。

StorageBtype1StorageBTypeは、異なるタイプであるので、それらの結果の種類も異なっていて、これらの関数の種類のいずれかの値が他の値として使用することができないように関数型は、それらを有します。

単にStorageBTypeに、すべてのコンバータ機能の結果の種類を変更します。

func TypeA3ToTypeB1(i StorageAType) StorageBType { 
    return StorageBType1{i.Type} 
} 

func TypeA5ToTypeB2(i StorageAType) StorageBType { 
    return StorageBType2{i.Type, i.Name} 
} 

すべての戻り値は、StorageBTypeを実装しているので、これは有効な変更で、コンバータ機能の実装に変更する必要はありません。

これらの関数を呼び出すと、タイプStorageBTypeの値が返されます。これで十分であれば、それ以上は何もできません。

インターフェイス値に格納されている具体的な型として戻り値が必要な場合は、type assertionを使用できます。例えば

a := StorageAType{Type:3} 
b := TypeA3ToTypeB1(a) // b is of type StorageBType 
if b1, ok := b.(StorageBType1); ok { 
    // b1 is of type StorageBType1, you may use it like so: 
    fmt.Println("b1.Type:", b1.Type) 
} else { 
    // b is not of type StorageBType1, or it is nil 
} 

出力:

b1.Type: 3 

あなたは、多くの具体的な種類をテストしたい場合は、あなたがtype switchを使用することがあります。

switch i := b.(type) { 
    case nil: 
     fmt.Println("nil") 
    case StorageBType1: 
     // Here i is of type StorageBType1, you may refer to its fields: 
     fmt.Println("StorageBType1", i.Type) 
    case StorageBType2: 
     // Here i is of type StorageBType2, you may refer to its fields: 
     fmt.Println("StorageBType2", i.Type, i.Name) 
    default: 
     fmt.Println("Unhandled type!") 
} 
関連する問題