2012-03-29 9 views
7

に割り当てる範囲/反復子は:D2:コードは以下の点を考慮アレイスライス

enum size = 16; 
double[size] arr1 = [...]; 
double[size] arr2 = [...]; 
process = (double x) { return (x + 1); }; 

arr2[] = map!(process)(arr1[]); // here 

私は普通アレイへ戻るmapのトラブル変換結果を有します。問題は、mapだけでなく、takerepeat、および範囲で動作するstd.algorithmstd.rangeのすべてのこれらの優れたツールにも適用されます。

この割り当てでは、Error: cannot implicitly convert expression (map(arr1[])) of type Result to double[]が得られます。

uint i = 0; 
foreach (x; map!(process)(arr1[])) { 
    arr2[i] = x; 
    i++; 
} 

を使用せずに範囲を評価する方法はありますか?

さらに、静的な配列でmap!(process)(arr1)の代わりにmap!(process)(arr1[])と呼ぶ必要がある理由を説明してもらえますか?静的配列は、反復の手段として動的と互換性がないはずですか、何か得られませんか?

さらに、列挙構文foreach (index, item; sequence)は範囲では機能しないようです - 回避策がありますか?理由は、範囲を配列スライスに割り当てることができない理由と同じだと思います。そのようなので、単にアレイに割り当てmapfilterリターン範囲ではなく、アレイとして

答えて

11

機能が動作しようとしているstringwstringに割り当てるよりも、それ以上の仕事に行くされていません。彼らは別のタイプです。また、多くの範囲ベースの関数(mapfilterを含む)では、不要な計算を避けるために返す範囲は実際には怠惰なので、配列との互換性がそれほど低下しません。解決策は、std.array.arrayを使用することです。これは範囲をとり、そこから動的配列を作成します。だから、あなたはあなたが実際に必要とする前に、それが不要な計算になりますので、私は、配列に範囲を変換しないで助言する、それは新しい配列を割り当てること、しかし

auto arr = array(map!process(origArray)); 

行うことができます。実際に配列が必要な場合は、必ずstd.array.arrayを使用して範囲を変換しますが、実際の配列を必要としない場合は範囲​​で操作する方が効率的です。しかし、結果をのstatic配列に変換する場合は、ループ内の各要素を代入するほうがよいでしょう(mapをスキップするのが良いでしょう)。std.array.array静的配列に割り当てたら、使用しない動的配列が割り当てられます。それは記憶の浪費です。

また、範囲ベース関数を持つ静的配列を使用すると、範囲ベース関数を処理するために静的配列をスライスして処理する必要があり、動的配列がスコープをエスケープする静的配列が宣言されていると、もはや存在しないデータへの参照が漏れています。たとえば、

auto func() 
{ 
    int[5] arr; 
    return map!process(arr[]); 
} 

は非常に悪いです。しかし、スライスの使用が終了し、何も参照していない限り(作成された可能性のある範囲を含む)、静的配列でスコープを終了する前に、正常であるはずです。それはでもです。

静的配列をスライスしなければならないことについての質問は、実際には別の質問として質問するべきですが、それに関連する2つの既存の質問はthis onethis oneです。 IFTI(Implicit Function Template Instantiation)は、与えられた正確な型を使用してインスタンス化され、静的配列も動的配列も範囲もないので、特に動的配列または範囲は静的配列でコンパイルできません。コンパイラは、静的配列を明示的にスライスして、明示的に動的配列をとる関数の動的配列に変換しますが、これらの暗黙的な変換はテンプレートのインスタンス化では起こらないため、静的配列を明示的にスライスして、ベースの関数です。

インデックスと範囲でforeachを使うことについての質問については、同じ質問で複数の質問をするべきではありません。あなたが持っている質問ごとに別々の質問を投稿してください。何それはしかしに降りてくることは

foreach(elem; range) 
{ 
    //stuff 
} 

for(; !range.empty; range.popFront()) 
{ 
    auto elem = range.front; 
    //stuff 
} 

に近いものに下げ取得し、それがすべてでインデックスを含まないということです。それはになりますあなたのためのインデックス変数を作成するために変更することができますが、常にすべての反復でそのような(通常は大丈夫だろう)と同じようにインデックスを反復する範囲を持っている意味がありませんので、されていません。あなた自身のカウンターを追加するだけでも簡単です。

{ 
    size_t i; 
    foreach(elem; range) 
    { 
     //stuff 
     ++i; 
    } 
} 

opApplyのforeachとインデックスを使用してサポートしていますが、それは範囲ではなく、範囲ベースの機能では動作しません。

+0

ありがとう、ジョナサン!範囲と配列は異なる型であることはわかっていますが、Dは有限で配列の型と型互換性がある限り、範囲は配列に変換できるため、Dは暗黙の変換を実装できると考えていました。私はスタックとヒープの割り当ての違い、そして配列izingの計算とメモリのオーバーヘッドを認識していますが、とにかく警告してくれてありがとう:) IFTIでこれを明確にしてくれてありがとう - 私はこの権利を理解すれば、暗黙的に静的な配列をスライスすることができますが、今は不完全さのためにこの方法を使用するべきです。 – toriningen

+0

静的配列を動的配列に暗黙的に変換するためにIFTI _might_を変更することはできますが、私はそれを疑っています。テンプレート化された関数を静的配列にすることは可能です(テンプレートのインスタンス化のために変換するのは悪くなります)。IFTIは暗黙の変換が見つかるまで試行し続けます。いくつかのテンプレートのセマンティクス)。だから、私は静的配列をスライスしてレンジベースの関数に渡す必要があると思っていますが、少なくとも問題を軽減するためにある点で改善がなされるかもしれません。 –

関連する問題