1

任意のタイプのスライスから要素をランダムに選択できる関数を実装しようとしています (python の random.choice 関数のように)

func RandomChoice(a []interface{}, r *rand.Rand) interface{} {
    i := r.Int()%len(a)
    return a[i]
}

ただし、[] float32 型のスライスを最初の引数に渡そうとすると、次のエラーが発生します。

cannot use my_array (type []float32) as type []interface {} in function argument

これはインターフェースの根本的な誤用ですか?{} これを行うためのより良い方法はありますか?

4

4 に答える 4

5

Re:これを行うためのより良い方法はありますか?

IMOがあります。OPアプローチは、単純なものに対して非効率的です。

var v []T
...

// Select a random element of 'v'
e := v[r.Intn(len(v))]   
...

len(v) == 0これの事前チェックが行われるまで、両方のアプローチがパニックになることに注意してください。

于 2013-02-28T07:22:42.063 に答える
2

リフレクションの使用:

func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
    x := reflect.ValueOf(slice)
    return x.Index(r.Intn(x.Len())).Interface()
}
于 2013-02-28T10:02:19.647 に答える
1

言語仕様から:

2つのタイプは同一または異なるものです。

2つの名前付きタイプは、それらのタイプ名が同じTypeSpecに由来する場合は同一です。名前付きタイプと名前なしタイプは常に異なります。対応する型リテラルが同一である場合、つまり、それらが同じリテラル構造を持ち、対応するコンポーネントが同一の型を持っている場合、2つの名前のない型は同一です。詳細に:

  • 2つの配列タイプは、同じ要素タイプと同じ配列長を持っている場合は同じです。
  • 2つのスライスタイプは、要素タイプが同じである場合は同じです。
  • 2つの構造体タイプは、フィールドのシーケンスが同じであり、対応するフィールドの名前が同じで、タイプが同じで、タグが同じである場合、同一です。2つの匿名フィールドは同じ名前であると見なされます。異なるパッケージの小文字のフィールド名は常に異なります。
  • 2つのポインタタイプは、基本タイプが同じである場合は同じです。
  • 2つの関数型は、パラメーターと結果の値が同じで、対応するパラメーターと結果の型が同じであり、両方の関数が可変引数であるか、どちらも可変でない場合、同一です。パラメータ名と結果名は一致する必要はありません。
  • 2つのインターフェイスタイプは、同じ名前と同じ関数タイプの同じメソッドセットがある場合、同じです。異なるパッケージの小文字のメソッド名は常に異なります。メソッドの順序は関係ありません。
  • 2つのマップタイプは、キーと値のタイプが同じである場合は同じです。
  • 2つのチャネルタイプは、同じ値タイプと同じ方向を持っている場合、同じです。

と:

次のいずれの場合でも、値xはタイプTの変数に割り当てることができます(「xはTに割り当てることができます」)。

  • xのタイプはTと同じです。
  • xのタイプVとTは同一の基礎となるタイプを持ち、VまたはTの少なくとも1つは名前付きタイプではありません。
  • Tはインターフェイスタイプであり、xはTを実装します。
  • xは双方向チャネル値、Tはチャネルタイプ、xのタイプVとTは同じ要素タイプであり、VまたはTの少なくとも1つは名前付きタイプではありません。
  • xは事前に宣言された識別子nilであり、Tはポインタ、関数、スライス、マップ、チャネル、またはインターフェイスタイプです。
  • xは、タイプTの値で表すことができる型なし定数です。

空白の識別子には任意の値を割り当てることができます。

[]MyTypeを[]interface{}に割り当てることができないこれら2つの結果の組み合わせ。

于 2013-02-28T07:07:50.533 に答える
0

まあ、すべての検索の後で、最初にリストされた関連する質問が次のようなものだったとはほとんど信じられません。答えがほとんど含まれているgoでインターフェースのスライスを変換するタイプ。その質問への回答で説明されている InterfaceSlice 関数を使用するように RandomChoice を変更すると、次のようになります。

func RandomChoice(slice interface{}, r *rand.Rand) interface{} {
    islice := InterfaceSlice(slice)
    i := r.Int()%len(islice)
    return islice[i] 
}

ただし、スライス全体を []interface{} に変換する必要があるため、この回答はあまりうまく機能していないようです...

于 2013-02-28T06:36:22.957 に答える