Arrays D动态数组初始化、跨步和索引操作

Arrays D动态数组初始化、跨步和索引操作,arrays,d,dynamic,stride,Arrays,D,Dynamic,Stride,很抱歉,关于阵列,这成了一个三重问题 我认为(动态)数组在D中确实很强大,但以下问题困扰了我一段时间: 在C++中,我可以很容易地分配一个数组,并指定值,但是在D中我没有找到这样的方法。以下几点肯定没有问题: int[] a = new int[N]; a[] = a0; 但是它看起来效率很低,因为第一行将使用0初始化,而第二行使用a0初始化。在D中是否可以执行类似于以下的操作 int[] a = new int(a0)[N]; // illegal 在标准范围内使用stride时,我遇到

很抱歉,关于阵列,这成了一个三重问题

我认为(动态)数组在D中确实很强大,但以下问题困扰了我一段时间:

在C++中,我可以很容易地分配一个数组,并指定值,但是在D中我没有找到这样的方法。以下几点肯定没有问题:

int[] a = new int[N];
a[] = a0;
但是它看起来效率很低,因为第一行将使用
0
初始化,而第二行使用
a0
初始化。在D中是否可以执行类似于以下的操作

int[] a = new int(a0)[N]; // illegal

在标准范围内使用stride时,我遇到的另一个效率问题是:

import std.stdio;
import std.range;

struct S
{
    int x;

    this(this)
    {
        writeln("copy ", x);
    }
}

void f(S[] s)
{
}

int main()
{
    S[] s = new S[10];
    foreach (i, ref v; s)
    {
        v.x = i;
    }

    f(stride(s, 3)); // error
    return 0;
}
我当然天真地认为我可以简单地使用stride创建一个新数组,而不复制它的元素?在D中没有这样做的方法,对吗


因此,我去模拟数组,好像stride将返回一样,并实现
f
为:

f(s, 3);

void f(S[] s, uint stride)
{
    ref S get(uint i)
    {
        assert (i * stride < s.length);
        return s[i * stride];
    }

    for (uint x ... )
    {
        get(x) = ...;
    }
}
f(s,3);
空f(S[]S,单位跨步)
{
参考S get(uint i)
{
断言(i*步幅
是否有一种方法可以代替使用索引操作符编写get(x)
get[x]
?这样我就可以静态地混合/包含striding
get
函数,并保持函数的其余部分相似。我对所采用的方法很感兴趣,因为不允许本地结构访问函数范围变量(为什么不?)。

您可以使用.dup复制(创建一个副本)数组(这也适用于切片),或者可以使用数组初始值设定项设置元素

int[] a=a0.dup;
int[] b=[e1,e2,e3];
您可以将f设置为泛型(stride()返回可以迭代的结构,而不是数组)

请记住,数组本质上是结构,带有指向某个内存块的指针字段和大小字段

但它看起来效率很低,因为第一行将初始化为0,而第二行初始化为a0。在D中是否可以执行类似于以下的操作

int[] a = new int(a0)[N]; // illegal
使用
std.array.uninitializedArray

S[] s = uninitializedArray!(S[])(N);
s[] = a0; 

我当然天真地认为我可以简单地使用stride创建一个新数组,而不复制它的元素?在D中没有这样做的方法,对吗

函数
f
的参数为
S[]
,这与
stride
返回的参数不同。解决此问题的D方法是通过将函数设置为模板,使其接受任何范围:

void f(Range)(Range s)
{
    foreach (item; s)
        // use item
}

S[] s = new S[10];
f(s); // works
f(stride(s, 3)); // works too
或者,您可以复制阵列:

f(array(stride(s, 3)));
但是,如果整个阵列很大,您可能希望避免复制它


是否有一种方法可以替代使用索引运算符get[x]编写get(x)?这样我就可以静态地混合/包含striding get函数,并保持函数的其余部分相似。我对所采取的方法感兴趣,因为不允许本地结构访问函数范围变量(为什么不?)

您可以在自己的结构中重载索引运算符

struct StrideArray
{
    this(S[] s, uint stride) { m_array = s; m_stride = stride; }

    S opIndex(size_t i) { return s[i * m_stride]; }
    void opIndexAssign(size_t i, S value) { s[i * m_stride] = value; }

    private S[] m_array;
    private uint m_stride;
}

这就是实际的
步幅
功能的工作方式。我建议您在上读一读。

谢谢您的阅读。虽然在某些构造中有轻微的性能损失(也许我滥用了它们),但代码更干净、更通用。为什么opIndex和opIndexAssign之间存在差异,opIndex不能简单地返回一个ref?性能问题已经解决。在将C库中的数组从指针转换为范围后,代码变得更加清晰。未发现速度差异。
void f(范围)(…)
应受到限制
isInputRange
?@Alexander:取决于他想做什么。如果他想写入范围,那么输入范围是不好的。我现在用isForwardRange约束它。我需要独立地读写这些值。如果a0是一个值,则dup成员不存在。做:
int[]b=[a0,a0,a0…(N次)]是一项艰苦的劳动。因此,除了使用元素的默认构造函数之外,无法分配数组(例如,对于相同的结构,将int设置为0以外的值)。