将数组参数传递给 D 函数的正确方法

问题描述 投票:0回答:2

第一个问题:

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)
arrays d
2个回答
13
投票
  1. 从技术上讲,像int[]这样的

    动态数组
    只是一个指针和一个长度。 只有指针和长度被复制到堆栈上,而不是数组内容。
    arr[0] = 42;
    确实会修改原始数组。
    另一方面,像 int[30] 这样的
    静态数组
    是一种普通的旧数据类型,由内存中的 30 个连续
    int
    组成。 因此,像
    void foo(int[30] arr)
    这样的函数首先会将 120 个字节复制到堆栈上。 在这种情况下,
    arr[0] = 42;
    修改数组的本地副本。

  2. 根据上面的内容,您列出的每种方法都可以避免复制数组内容。 因此,您是否需要参数为

    const
    in
    const ref
    或其他,取决于除了避免数组复制之外您想要实现的目标。 例如,如果您传递一个
    ref int [] arr
    参数,您不仅可以修改其内容,还可以修改指针和长度(例如,创建一个全新的数组并将其分配给
    arr
    ,这样从函数外部可见)。

欲了解更多信息,请参阅 DLang 网站上的相应文章,涵盖 arraysarray slices


0
投票

根据我从文档中了解到的信息,静态数组意味着通过值传递,动态数组通过引用传递。然而,实际情况并非如此。这取决于函数参数的类型声明。

静态数组是按值传递的,除非您在函数参数的类型中指定数组大小。我不确定这是它的预期方式还是编译器错误?看起来确实有点古怪。一方面,它将允许您修改函数中数组的长度,而静态数组不允许这样做。如果您要使用数组指针来执行此操作,文档明确指出该行为是未定义的。

这是我刚刚编写的快速测试。请注意,按值传递的唯一方法是在函数参数中指定 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 );
    

}
© www.soinside.com 2019 - 2024. All rights reserved.