13

チャネルから消費されるすべての要素からスライスを作成するにはどうすればよいですか (Python のようlistに)? このヘルパー関数を使用できます。

func ToSlice(c chan int) []int {
    s := make([]int, 0)
    for i := range c {
        s = append(s, i)
    }
    return s
}

しかし、 genericsがないため、すべての型についてそれを書かなければなりませんよね? これを実装する組み込み関数はありますか? そうでない場合、使用しているすべてのタイプに対して上記のコードをコピーして貼り付けないようにするにはどうすればよいですか?

4

2 に答える 2

8

コードに変換が必要なインスタンスが数回しかない場合は、7 行のコードを数回コピーしてもまったく問題はありません (または、使用されている場所にインライン化することで、4 行のコードに削減され、おそらく最も読みやすいソリューション)。

非常に多くの種類のチャネルとスライスの間で変換があり、汎用的なものが必要な場合は、ChanToSlice の呼び出しサイトでの醜さと静的型付けの欠如を犠牲にして、リフレクションを使用してこれを行うことができます。

これは、reflect を使用してこの問題を解決する方法の完全なサンプル コードであり、int チャネルで動作するデモを示しています。

package main

import (
    "fmt"
    "reflect"
)

// ChanToSlice reads all data from ch (which must be a chan), returning a
// slice of the data. If ch is a 'T chan' then the return value is of type
// []T inside the returned interface.
// A typical call would be sl := ChanToSlice(ch).([]int)
func ChanToSlice(ch interface{}) interface{} {
    chv := reflect.ValueOf(ch)
    slv := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf(ch).Elem()), 0, 0)
    for {
        v, ok := chv.Recv()
        if !ok {
            return slv.Interface()
        }
        slv = reflect.Append(slv, v)
    }
}

func main() {
    ch := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
    }()
    sl := ChanToSlice(ch).([]int)
    fmt.Println(sl)
}
于 2013-12-05T09:39:52.797 に答える
6

ToSlice() を interface{} だけで動作させることもできますが、ここで節約するコードの量は、他の場所での複雑さを犠牲にする可能性があります。

func ToSlice(c chan interface{}) []interface{} {
    s := make([]interface{}, 0)
    for i := range c {
        s = append(s, i)
    }
    return s
}

http://play.golang.org/p/wxx-Yf5ESNの完全な例

つまり、@Volkerがあなたが示したコードのスライス(笑)からのコメントで言ったように、結果をストリーミング方式で処理するか、ジェネレーターで「それらをバッファリング」して送信する方が賢明なようですチャネルを下にスライスします。

于 2013-12-05T01:54:05.767 に答える