4

There are comparatively many storage class specifiers for functions arguments in D, which are:

  • none
  • in (which is equivalent to const scope)
  • out
  • ref
  • scope
  • lazy
  • const
  • immutable
  • shared
  • inout

What's the rational behind them? Their names already put forth the obvious use. However, there are some open questions:

  1. Should I use ref combined with in for struct type function arguments by default?
  2. Does out imply ref implicitely?
  3. When should I use none?
  4. Does ref on classes and/or interfaces make sense? (Class types are references by default.)
  5. How about ref on array slices?
  6. Should I use const for built-in arithmetic types, whenever possible?

More generally put: When and why should I use which storage class specifier for function argument types in case of built-in types, arrays, structs, classes and interfaces? (In order to isolate the scope of the question a little bit, please don't discuss shared, since it has its own isolated meaning.)

4

1 に答える 1

4
  1. デフォルトではどちらも使用しません。refパラメータは左辺値のみを取り、渡される引数を変更することを意味します。コピーを避けたい場合は、const refまたはを使用してくださいauto ref。ただし、const ref それでも左辺値が必要なため、関数を複製したい場合を除いて、その価値よりも煩わしいことがよくあります。また、auto ref左辺値のコピーを回避しますが(基本的に、左辺値refを受け取る関数となしで右辺値を受け取る関数のバージョンが存在するようになりますref)、テンプレートでのみ機能し、その有用性が制限されます。また、Dは推移的であり、キャストするのは未定義の動作であるため、使用constすると広範囲にわたる結果が生じる可能性があります。constconst変数から変更します。そのため、多くの場合便利ですが、デフォルトで使用すると問題が発生する可能性があります。

    を使用すると、に加えて、一般的にはinお勧めしません。on関数パラメーターは、そのデータへの参照が関数をエスケープできないようにすることになっていますが、そのチェックはまだ適切に実装されていないため、実際には、正当であると想定されるよりもはるかに多くの状況で使用できます。非常に貴重な場合があります(たとえば、コンパイラがクロージャを割り当てる必要がないようにするため、デリゲートを使用する場合)が、他のタイプの場合は、煩わしい場合があります(たとえば、配列を渡す場合は、その場合、関数からその配列にスライスを返すことができませんでした)。また、配列または参照型を持つ構造体も影響を受けます。そして、あなたは間違って使用することについて多くの不満を得ることがありませんがscopeconstscopescopescopescope今のところ、あちこちで使用している場合は、修正すると多くのエラーが発生するはずです。また、値型にはエスケープへの参照がないため、まったく意味がありません。したがって、値型(値型である構造体を含む)での使用constと使用は実質的に同じです。in

  2. outは、refパラメータをそのinit値にリセットすることを除いて同じです。これにより、渡される変数の以前の状態に関係なく、常に同じ値が渡されます。

  3. ほとんどの場合、関数の引数に関する限り。特定のニーズがある場合はorを使用しますが、デフォルトではそれらのいずれかを使用することはお勧めしませconstん。scope

  4. もちろんそうです。refクラス参照の概念とは別のものです。これは、渡される変数への参照です。

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

    new MyClass(7)次に、varは、の呼び出し後に新しく構築されたを参照し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で引数を取らなかった場合はrefvarスライスされ、に追加しarrても影響はありませんでしたvar。しかし、パラメータがだったので、に行われたことはすべてに行われrefます。arrvar

  6. それは完全にあなた次第です。変更できないようにconstすることで、変更するつもりがない場合に誤って変更することから保護されます。いくつかの最適化も可能になる場合がありますが、変数に書き込むことがなく、組み込みの算術型である場合、コンパイラは変数が変更されないことを認識し、オプティマイザはとにかくそれらの最適化を実行できるはずです(コンパイラの実装に依存しません)。

    immutableconstほとんどすべての場合、組み込みの算術型と実質的に同じであるため、個人的には、そのimmutableような変数が変更されないことを保証したい場合に使用します。一般に、 ifimmutableの代わりにを使用するとconst、最適化と保証が向上します。これは、変数をスレッド間で暗黙的に共有できるようにし(該当する場合) 、変数を変更できないことを常に保証するためです(参照型の場合、const単に、その参照がオブジェクトを変更できないことを意味するだけであり、変更できないことを意味するのではありません)。

    確かに、変数constimmutableできるだけ多くのマークを付けると、少なくとも一部の時間はコンパイラーの最適化に役立ち、意図しないときに何かを変更したバグを簡単に見つけることができます。また、変数が変更されないことがわかっているため、コードを理解しやすくすることもできます。したがって、それらを自由に使用することは価値があります。ただし、タイプによっては、constまたはの使用immutableが過度に制限される可能性があるため(組み込みの整数型では問題ありません)、すべてを自動的にマークするconstimmutable、問題を引き起こす可能性があります。

于 2012-08-29T17:36:30.550 に答える