Return 用D语言理解refs

Return 用D语言理解refs,return,d,ref,Return,D,Ref,比如说,我想加上两个向量(在数学意义上)的数值。当然,我会这样做: T[] add(T)(T[] a, T[] b) { assert(a.length == b.length); T[] res = a.dup; foreach (i; 0 .. a.length) { res[i] = a[i] + b[i]; } return res; } 好吧,没关系,但我怀疑a和b会抄袭每一个电话,这不是很好。所以我声明它们ref T[] add

比如说,我想加上两个向量(在数学意义上)的数值。当然,我会这样做:

T[] add(T)(T[] a, T[] b) {
    assert(a.length == b.length);
    T[] res = a.dup;
    foreach (i; 0 .. a.length) {
        res[i] = a[i] + b[i];
    }
   return res;
}
好吧,没关系,但我怀疑
a
b
会抄袭每一个电话,这不是很好。所以我声明它们
ref

T[] add(T)(ref T[] a, ref T[] b) { ...
它在传递变量时工作得很好,但对于测试,我使用数组实例:

assert(add([1, 2, 3], [4, 5, 6]) == [5, 7, 9]);
这失败了,因为它无法推断数组的引用。我设法找到了一个解决办法:

T[] add(T)(T[] a, T[] b) {
    return add(a, b);
}
这似乎解决了问题,但看起来相当愚蠢。对于我的问题,什么是更好的设计

或者把它放到更小的问题中:我真的必须将参数声明为
ref
以避免复制吗?由于我没有修改
a
b
,编译器能为我优化这个吗?顺便问一下,我如何声明参数是不可变的(我尝试了
immutable
关键字,看起来我用错了)?在解决方案中,
res
真的会被复制两次,还是通过移动来返回?

你真的应该阅读。它详细介绍了D中的数组是如何工作的。但作为一个简短的回答,当将参数传递给

T[] add(T)(T[] a, T[] b) {...}
是指针的基础指针和长度。没有复制任何元素。相反,数组是“切片的”。
add
中的结果数组是
add
参数的切片,这意味着它们引用的内存与原始数组相同。变异切片的元素将变异原始数组的元素,因为它们是相同的元素。但是,对数组本身进行变异(例如,将另一个数组分配给它或附加到它)不会影响原始数组,并且如果附加到该数组会导致重新分配其内存以腾出空间(或者如果将新数组分配给该数组),则该数组将不再引用与原始数组相同的元素。在代码中,制作数组副本的唯一位置是
a.dup

ref
标记数组所做的是使其不被切片。相反,它们是原始数组而不是切片。因此,如果将任何内容附加到本地数组或重新分配,则会影响原始数组(而如果未使用
ref
,则不会影响原始数组)

另外,
ref
只接受左值(意味着可以在赋值的左侧出现的值),数组文字是右值(意味着它们只能在赋值的右侧出现),因此不能将它们传递给以
ref
为参数的函数。如果您想同时接受这两个版本,您要么必须通过
ref
不接受,要么重载您的函数,使您拥有
ref
和非
ref
版本(这两个版本显示为您使用的解决方案),要么使用
auto ref
而不是
ref
,在这种情况下,它将同时接受这两个版本(但是,
auto-ref
只适用于模板化函数,它基本上只是自己复制函数的简写,因为这就是
auto-ref
所做的)。不过,一般来说,如果您不想对原始函数进行变异,就不应该经过
ref

T[] add(T)(ref T[] a, ref T[] b) { ...
提高代码速度的一个建议是:没有理由重复
a
a
,然后再次循环,并将其与
b
一起添加。如果这是您想要做的,您最好只使用
+=
并执行类似的操作

T[] add(T)(T[] a, T[] b)
{
    assert(a.length == b.length);
    auto res = a.dup;
    foreach (i; 0 .. a.length)
        res[i] += b[i];
   return res;
}
或者更好,您可以使用并完全跳过循环:

T[] add(T)(T[] a, T[] b)
{
    assert(a.length == b.length);
    auto res = a.dup;
    res[] += b[];
    return res;
}

但同样,如果你想正确理解数组在D中的工作原理,你真的应该读一读。

@ratchetfreak,它看起来确实能工作,这会更好。我对数组向量运算不是很精通,所以我不知道你能做什么和不能做什么。我试过
a[]+b[]
,它不起作用并放弃了。但是由于
res+=b[]
起作用,我将相应地更新我的答案。