0

次のコードを書き直すにはどうすればよいですか?

switch md.(type) {
    case *amf0.EcmaArrayType:
        ea := md.(*amf0.EcmaArrayType)
        for k, v := range (*ea) {
            log.Printf("%v = %v\n", k, v)
        }
        if width == 0 {width = uint16((*ea)["width"].(amf0.NumberType))}
        if height == 0 {height = uint16((*ea)["height"].(amf0.NumberType))}
    case *amf0.ObjectType:
        ea := md.(*amf0.ObjectType)
        for k, v := range (*ea) {
            log.Printf("%v = %v\n", k, v)
        }
        if width == 0 {width = uint16((*ea)["width"].(amf0.NumberType))}
        if height == 0 {height = uint16((*ea)["height"].(amf0.NumberType))}
}

異なるタイプの 2 つの完全に複製されたブロックがあります。var ea interface{}上記のスイッチ状態を宣言range (*ea)すると、コンパイルエラーで呼び出すことができません。

4

3 に答える 3

2

これらのタイプは両方とも、map[string]something「何か」が具体的なタイプを持つ基本的なタイプを持っているようですamf0.NumberType。実行したすべての操作は、リフレクションを使用してエミュレートできます。

switch md.(type) {
case *amf0.EcmaArrayType, *amf0.ObjectType:
    m := reflect.Indirect(reflect.ValueOf(md))
    for _, key := range m.MapKeys() {
        k, v := key.Interface(), m.MapIndex(key).Interface()
        log.Printf("%v = %v\n", k, v)
    }

    if width == 0 {
        w := m.MapIndex(reflect.ValueOf("width"))
        width = uint16(w.Interface().(amf0.NumberType))
    }

    if height == 0 {
        h := m.MapIndex(reflect.ValueOf("height"))
        height = uint16(h.Interface().(amf0.NumberType))
    }
}

ただし、最初の例で行ったことを行うことは珍しくありません。リフレクトが効かない時があります。その場合、タイプの切り替えについてアドバイスがあります。switch md.(type)する代わりにswitch ea := md.(type)。これにより、 のような行を削除できますea := md.(*amf0.EcmaArrayType)

DRY コードの方が使いやすいです。これにより、変更がより迅速に行われ、バグが発生しにくくなります。ただし、複製されたコードがすべて 1 か所 (タイプ スイッチなど) にある場合は、バグの可能性はほとんどありません。変更を加えるにはまだ時間がかかりますが、プロジェクト全体でコードが重複するほど悪くはありません。他の重複したコードのように、型スイッチが大幅に重複することを恐れないでください。

于 2012-11-11T18:55:10.353 に答える
1

この特定のケースでは、重複したコードを指摘する将来のメンテナーにコメントを追加するか、次のように削除する可能性があります。(プレイグラウンド: http://play.golang.org/p/Vc9pOZSNoW )

package main

import "log"

// copied from package amf0
type NumberType float64
type StringType string
type _Object map[StringType]interface{}
type ObjectType _Object
type EcmaArrayType _Object

// test parameter.  comment out one or the other
// var md interface{} = &ObjectType{"height": NumberType(3), "width": NumberType(5)}
var md interface{} = &EcmaArrayType{"height": NumberType(5), "width": NumberType(7)}

func main() {
    var width, height uint16
    ea, ok := md.(*ObjectType)
    if !ok {
        if et, ok := md.(*EcmaArrayType); ok {
            ea = (*ObjectType)(et)
        }
    }
    if ea != nil {
        for k, v := range *ea {
            log.Printf("%v = %v\n", k, v)
        }
        if width == 0 {
            width = uint16((*ea)["width"].(NumberType))
        }
        if height == 0 {
            height = uint16((*ea)["height"].(NumberType))
        }
    }
}

オリジナルの複製されたコードは複製されたソース コードにすぎません。異なる型を処理していたため、コンパイルされたコードは異なりました。幸いなことに、ObjectType の場合のコンパイル済みコードは、ea = (*ObjectType)(et) の単純な型変換で EcmaArrayType の場合を簡単に処理できます。

于 2012-11-11T19:14:51.667 に答える
0

範囲を呼び出す前に型キャストを使用します。例:

     range ((* your_desired_type)(*ea))

your_desired_type型キャストの場合は、を実際の型に置き換えてください。

于 2012-11-11T15:57:12.680 に答える