2

typedefが与えられた場合: "type ID int"

map[ID]intをmap[int]intに変換することは可能ですか?

私はもう試した:

map[int]int(m)

と同様

m.(map[int]int)

どちらも機能していないようです:http: //play.golang.org/p/oPzkUcgyaR

何かアドバイス?


数人が尋ねたので、詳細を編集します。

私がやろうとしているのは、リーグを決めることです。

たくさんの「チーム」があり、それぞれにいくつかの統計があります。統計ごとに、最高得点で10ポイント、2位で9ポイントを獲得します。

私はこれを次のようにモデル化しました:

// Each team's statistics:
type StatLine map[StatID]float64

// The whole league:
map[TeamID]StatLine

// And I want to score that whole league with:
func score(s map[TeamID]StatLine) map[TeamID]int

// Only, is't also handy to score individual players:
func score(s map[PlayerID]StatLine) map[PlayerID]int

また、score()を2回記述したり(同じロジックであるため)、マップ全体をコピーしたりしないのは素晴らしいことです。

PlayerIDとTeamIDがintであることがあるので、score(s map [int] int)を記述して、型変換を実行できるかどうか知りたいと思いました。ただし、SteveMcQwarkは、これが悪い考えである理由を明確にしています。

ジェネリックはこれを解決すると思いますが、すぐには出てこないことはわかっています。他のアイデアはありますか?

ありがとう!

4

3 に答える 3

2

Goでジェネリックスを本当に実行したい場合は、インターフェースが必要です。このインターフェースは、チーム用とプレーヤー用の2つのタイプで実装されます。スコア関数は、このインターフェイスタイプのオブジェクトを引数として取り、チームまたはプレーヤーのどちらで機能しているかを知らなくても、一般的なスコアリングロジックを実装します。これが概要です。詳細は次のとおりです。

インターフェイスのメソッドセットは、スコア関数が必要とする関数とまったく同じになります。必要と思われる2つの方法から始めましょう。

type scoreable interface {
    stats(scID) StatLine  // get statLine for ID
    score(scID, int)      // set score for ID
}

および一般的なスコアリング可能なIDタイプ、

type scID int

このインターフェースを実装できるタイプは、TeamIDとPlayerIDではなく、それらのマップを保持するタイプです。さらに、これらの各タイプには、マップ、StatLineおよびスコアマップの両方が必要になります。構造体はこれで機能します:

type teamScores struct {
    stats map[TeamID]StatLine
    scores map[TeamID]int
}

スコアリング可能な実装、

func (s *teamScores) stats(id scID) StatLine {
    return s.stats[TeamID(id)]
}

func (s *teamScores) score(id scID, sc int) {
    s.scores[TeamID(id)] = sc
}

待って、あなたは言うかもしれません。scIDからTeamIDへのその型変換。安全ですか?TeamIDさえも持たないという低エンジニアリングのアプローチを採用したほうがよいでしょうか。まあ、これらの方法が賢明に使われている限り、それは安全です。構造体teamScoresは、TeamIDのマップをTeamIDの別のマップに関連付けます。間もなく作成されるジェネリック関数スコアは、この構造体を引数として取り、正しい関連付けが与えられます。TeamIDとPlayerIDを混同することはできません。これは価値があり、十分な規模のプログラムではこの手法を正当化できます。

PlayerIDについても同じことを行い、同様の構造体を定義して、2つのメソッドを追加します。

スコア関数を1回記述します。このように開始します:

func score(s scoreable) {
    for

おっと、反復する方法が必要です。便利な解決策は、IDのリストを取得することです。そのメソッドを追加しましょう:

type scoreable interface {
    ids() []scID          // get list of all IDs
    stats(scID) StatLine  // get statLine for ID
    score(scID, int)      // set score for ID
}

およびteamScoresの実装:

func (s *teamScores) ids() (a []scID) {
    for tid := range s.stats {
        a = append(a, scID(tid))
    }
    return
}

今、私たちはどこにいましたか?

func score(s scoreable) {
    // lets say we need some intermediate value
    sum := make(map[scID]float64)
    // for each id for which we have a statLine,
    for _, id := range s.ids() { // note method call
        // get the statLine
        stats := s.stats() // method call
        // compute intermediate value
        sum[id] = 0.
        for _, statValue := range stats {
            sum[id] += statValue
        }
    }
    // now compute the final scores
    for id, s := range sum {
        score := int(s) // stub computation
        s.score(id, score) // method call
    }
}

この関数は、* scoreableのようなインターフェースへのポインターではなく、scoreableのインターフェースタイプをとることに注意してください。インターフェイスは、ポインタ型*teamScoresを保持できます。インターフェイスへの追加のポインタは適切ではありません。

最後に、ジェネリック関数を呼び出すには、teamScores型のオブジェクトが必要です。おそらくすでにリーグ統計を持っていますが、スコアマップをまだ作成していない可能性があります。このように一度にすべてを行うことができます:

ts := &teamScores{
    stats:  ...your existing map[TeamID]Statline,
    scores: make(map[TeamID]int),
}

電話:

score(ts)

そして、チームのスコアはts.scoresになります。

于 2012-05-29T18:31:16.903 に答える
0

変換ルールは、表現力と保守性の間のトレードオフです。2つのタイプ間で変換するときはいつでも、それらのタイプが将来も表現的および論理的に互換性を維持するという賭けをしていることになります。型システムの目標の1つは、この互換性への依存の広がりを最小限に抑えることです。一方、同じデータを操作できる複数のメソッドセットを定義できると非常に便利です。変換により、既存のデータを操作するために必要に応じて適切なメソッドセットを選択できます。変換を実行できるのは、他の点では同一の型のメソッドセットを合法的に交換できる場合のみです。これは、質問している場合を除きます。

どのようにしようとしているのかではなく、何をしようとしているのかを知ることが役立つ場合があります。つまり、読み取り専用アクセスが必要な場合は、をラップするか、を使用できますが、これが不要である可能性は十分にあります。map[ID]intfunc(int)(int, bool)interface { Get(int)(int, bool); Set(int, int); Delete(int) }

于 2012-05-28T20:13:48.313 に答える
0

TeamIDとPlayerIDのタイプを別々にするのは過剰設計である可能性があります。両方に同じタイプ、たとえばScoreableIDを使用した場合、問題は解決します。ほとんどの場合、変数名、関数名、またはプログラムコンテキストにより、何かがプレーヤーであるかチームであるかが明確になります。コメントは、残りのあいまいなコードに適切です。

于 2012-05-29T16:32:27.083 に答える