第一个问题:
D 数组函数参数总是按引用传递还是按值传递? 另外,该语言是否为数组实现了 Copy on Write ? 例如:
void foo(int[] arr)
{
// is arr a local copy or a ref to an external array?
arr[0] = 42; // How about now?
}
第二个问题:
假设我有一个大数组,将作为只读参数传递给函数
foo
,并且应该尽可能避免复制该数组,因为它被假定为一个非常大的对象。以下哪一个(或没有一个)是函数的最佳声明 foo
:
void foo(const int[] bigArray)
void foo(in int[] bigArray)
void foo(const ref int[] bigArray)
从技术上讲,像int[]
这样的
动态数组只是一个指针和一个长度。 只有指针和长度被复制到堆栈上,而不是数组内容。
arr[0] = 42;
确实会修改原始数组。int[30]
这样的静态数组是一种普通的旧数据类型,由内存中的 30 个连续
int
组成。 因此,像 void foo(int[30] arr)
这样的函数首先会将 120 个字节复制到堆栈上。 在这种情况下,arr[0] = 42;
修改数组的本地副本。根据上面的内容,您列出的每种方法都可以避免复制数组内容。 因此,您是否需要参数为
const
、in
、const ref
或其他,取决于除了避免数组复制之外您想要实现的目标。 例如,如果您传递一个ref int [] arr
参数,您不仅可以修改其内容,还可以修改指针和长度(例如,创建一个全新的数组并将其分配给arr
,这样从函数外部可见)。欲了解更多信息,请参阅 DLang 网站上的相应文章,涵盖 arrays 和 array slices。
根据我从文档中了解到的信息,静态数组意味着通过值传递,动态数组通过引用传递。然而,实际情况并非如此。这取决于函数参数的类型声明。
静态数组是按值传递的,除非您在函数参数的类型中指定数组大小。我不确定这是它的预期方式还是编译器错误?看起来确实有点古怪。一方面,它将允许您修改函数中数组的长度,而静态数组不允许这样做。如果您要使用数组指针来执行此操作,文档明确指出该行为是未定义的。
这是我刚刚编写的快速测试。请注意,按值传递的唯一方法是在函数参数中指定 int[3] :
void main{
int[3] arr_s;
arr_s[] = 4;
// arr_s.length = 10; // ERROR: cannot be done for a static array
writeln( "before call ", arr_s );
function_byValue( arr_s, arr_s.ptr );
writeln( "after call ", arr_s );
writeln( "before call ", arr_s );
function_byRef( arr_s, arr_s.ptr );
writeln( "after call ", arr_s );
}
void function_byValue(int[3] arr_s, int* p_s ){
assert( arr_s.ptr != p_s );
//arr_s.length = 10;
arr_s[1] = 33;
writeln( "during call ", arr_s );
}
void function_byRef(int[] arr_s, int* p_s ){
assert( arr_s.ptr == p_s );
//arr_s.length = 10;
arr_s[1] = 33;
writeln( "during call ", arr_s );
}