d2:将范围/迭代器分配给数组切片

tor*_*gen 7 iterator d range

考虑以下代码:

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

arr2[] = map!(process)(arr1[]); // here
Run Code Online (Sandbox Code Playgroud)

我无法将结果转换map回我的普通数组.问题不仅适用于map,而且要take,repeat并从所有这些精细的工具std.algorithm,并std.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++;
}
Run Code Online (Sandbox Code Playgroud)

另外,有人可以解释,为什么我必须调用map!(process)(arr1[])而不是map!(process)(arr1)静态数组?静态数组不应该与动态的迭代方法兼容,或者我没有得到什么?

此外,似乎简单的枚举语法foreach (index, item; sequence)不适用于范围 - 是否有解决方法?我想原因与为什么范围不能分配给数组切片的原因相同.

Jon*_*vis 11

诸如mapfilter返回范围之类的函数,而不是数组,所以简单地分配给数组不会比分配一个stringto 工作更wstring有效.他们是不同的类型.对于许多基于范围的函数(包括mapfilter),它们返回的范围实际上是惰性的,以避免不必要的计算,这使得它们与数组的兼容性更低.解决方案是使用std.array.array,它接受一个范围并从中创建动态数组.所以,你可以这样做

auto arr = array(map!process(origArray));
Run Code Online (Sandbox Code Playgroud)

但是,我建议不要在实际需要之前将范围转换为数组,因为它可能导致不必要的计算,这意味着分配一个新数组.如果您确实需要一个数组,那么请务必使用std.array.array转换范围,但如果您不需要实际数组,则在该范围上运行通常会更有效.但是,如果你想将结果转换为静态数组而不是动态数组,那么你最好只是在循环中分配每个元素(并且可能map完全跳过),因为使用std.array.array会有分配了一个动态数组,一旦分配给静态数组,就不会使用它.这是浪费记忆.

此外,请注意,使用具有基于范围的函数的静态数组可能存在风险,因为它们必须切片静态数组以获取动态数组以供基于范围的函数进行处理,并且如果该动态数组转义了静态数组的范围声明,然后你泄漏了对不再存在的数据的引用.例如,

auto func()
{
    int[5] arr;
    return map!process(arr[]);
}
Run Code Online (Sandbox Code Playgroud)

会很糟糕的.但是,只要你完成使用切片并且在退出带有静态数组的范围之前没有任何东西引用它(包括可能已经创建的任何范围),你应该没问题.这东西要小心,虽然.

至于必须切片静态数组的问题,你真的应该问这是一个单独的问题,但是与它相关的两个现有问题是这一个这一个.它几乎归结为IFTI(隐式函数模板实例化)使用它给出的确切类型实例化,静态数组既不是动态数组也不是范围,因此任何模板化函数都需要动态数组或者range将无法使用静态数组进行编译.编译器隐式切片静态数组以将它们转换为动态数组,用于显式获取动态数组的函数,但这种隐式转换不会发生在模板实例化中,因此必须显式切片静态数组以将它们传递给基于范围的函数.

至于将foreach与指数和范围一起使用的问题,再次,你不应该在同一个问题中提出多个问题.请为您提出的每个问题发布单独的问题.它归结为什么呢

foreach(elem; range)
{
    //stuff
}
Run Code Online (Sandbox Code Playgroud)

降低到接近的程度

for(; !range.empty; range.popFront())
{
    auto elem = range.front;
    //stuff
}
Run Code Online (Sandbox Code Playgroud)

而这根本不涉及指数.这可能是改变为您创建一个索引变量,但它并不总是有意义的范围由一个像在每个迭代上(就像它通常会被罚款)有他们的索引迭代,所以还没有已经完成了.虽然添加自己的计数器很简单.

{
    size_t i;
    foreach(elem; range)
    {
        //stuff
        ++i;
    }
}
Run Code Online (Sandbox Code Playgroud)

opApply 确实支持使用带有foreach的索引,但它不是范围,并且不适用于基于范围的函数.