我应该如何在D中的函数参数中使用存储类说明符,如ref,in,out等?

时间:2012-08-29 15:57:45

标签: reference arguments d storage-class-specifier

D中的函数参数有相对多的存储类说明符,它们是:

  • in(相当于const scope
  • out
  • ref
  • scope
  • lazy
  • const
  • immutable
  • shared
  • inout

他们背后的理性是什么?他们的名字已经提出了明显的用途。但是,有一些悬而未决的问题:

  1. 默认情况下,我应该将refin结合使用struct类型的函数参数吗?
  2. out暗示ref是否含蓄?
  3. 我应该何时使用 none
  4. 类和/或接口上的ref是否有意义? (默认情况下,类类型是引用。)
  5. 数组切片上ref怎么样?
  6. 我应该尽可能使用const内置算术类型吗?
  7. 更一般地说:在内置类型,数组,结构,类和接口的情况下,何时以及为什么我应该使用哪个存储类说明符用于函数参数类型? (为了稍微区分问题的范围,请不要讨论shared,因为它有其独立的含义。)

1 个答案:

答案 0 :(得分:4)

  1. 默认情况下我也不会使用。 ref参数只接受左值,这意味着你将改变传入的参数。如果你想避免复制,那么使用const refauto ref。但是const ref 仍然需要一个左值,所以除非你想要复制你的函数,否则它通常比它的价值更令人讨厌。虽然auto ref将避免复制左值(它基本上使得它有一个函数的版本,它采用ref的左值和一个不使用ref的rvalues,它只能工作使用模板,限制其有用性。使用const可能会产生深远的影响,因为D const具有传递性,并且事实上,从变量中抛弃const并修改它是未定义的行为。因此,虽然它通常很有用,但默认使用它可能会让你陷入困境。

    使用inscope之外还提供const,我通常会建议您这样做。关于函数参数的scope应该使它不会引用该数据,但是对它的检查还没有正确实现,所以实际上你可以在很多情况下使用它。应该是合法的。在某些情况下,scope是无价的(例如,使用委托,因为它使得编译器不必为它分配闭包),但对于其他类型,它可能很烦人(例如,如果你传递一个数组scope,然后你不能从该函数返回一个切片到该数组)。任何包含任何数组或引用类型的结构都会受到影响。虽然你现在不会对错误地使用scope提出很多抱怨,但如果你一直在使用它,那么一旦修复它就会遇到很多错误。此外,它对于值类型完全没有意义,因为它们没有提到逃避。因此,在值类型(包括值类型的结构)上使用constin实际上是相同的。

  2. outref相同,只是它将参数重置为其init值,这样无论先前的状态如何,您都会获得相同的值传入的变量是。

  3. 几乎总是就函数参数而言。如果您有特殊需要,可以使用constscope或其他内容,但默认情况下我不建议使用其中任何一个。

  4. 当然可以。 ref与类引用的概念是分开的。它是对传入的变量的引用。如果我这样做

    void func(ref MyClass obj)
    {
        obj = new MyClass(7);
    }
    
    auto var = new MyClass(5);
    func(var);
    

    然后var将在调用new MyClass(7)而不是func之后引用新构建的new MyClass(5)。您正在通过ref传递引用。这就像获取引用的地址(如var)为您提供指向引用的指针以及而不是指向类对象的指针一样。

    MyClass* p = &var; //points to var, _not_ to the object that var refers to.
    
  5. 与班级相同的交易。 ref使参数引用传入的变量。例如

    void func(ref int[] arr)
    {
        arr ~= 5;
    }
    
    auto var = [1, 2, 3];
    func(var);
    assert(var == [1, 2, 3, 5]);
    

    如果func没有按ref进行论证,那么var就会被切片,而arr的追加也不会影响var 。但由于参数为ref,因此对arr所做的任何事情均由var完成。

  6. 这完全取决于你。使它成为const使得你不能改变它,这意味着如果你不打算改变它,你就会受到保护而不会意外地改变它。 可能也可以启用一些优化,但是如果你从不写入变量,并且它是内置的算术类型,那么编译器知道它永远不会改变,优化器应该能够进行那些优化无论如何(不管它是否取决于编译器的实现)。

    几乎在所有情况下,

    immutableconst对于内置算术类型实际上是相同的,所以就我个人而言,如果我想保证这样的话,我只会使用immutable变量不会改变。通常,使用immutable而不是const如果可以为您提供更好的优化和更好的保证,因为它允许变量在线程之间隐式共享(如果适用)并且总是保证变量不能被变异(而对于引用类型,const仅仅意味着该引用不能改变对象,而不是它不能被变异)。

    当然,如果你尽可能地标记变量constimmutable,那么它确实至少在某些时候帮助编译器进行优化,并且它可以更容易地捕获错误当你不是故意的时候,你突然改变了什么。它还可以使您的代码更容易理解,因为您知道变量不会被变异。因此,大量使用它们可能很有价值。但同样,使用constimmutable可能过于严格,具体取决于类型(尽管这不是内置整数类型的问题),因此只需将所有内容自动标记为{{1} }或const会导致问题。