17

このようなもの(はい、これはいくつかのエッジケースを扱いません-それはポイントではありません):

int CountDigits(int num) {
    int count = 1;
    while (num >= 10) {
        count++;
        num /= 10;
    }
    return count;
}

これについてどう思いますか?つまり、関数の引数をローカル変数として使用します。
どちらもスタックに配置されており、パフォーマンスに関してはほぼ同じですが、これのベストプラクティスの側面について疑問に思っています。
で構成されるその関数に追加の非常に冗長な行を追加すると、ばかみたいに感じますがint numCopy = num、それは私を悩ませます。
どう思いますか?これは避けるべきですか?

4

9 に答える 9

18
  1. 原則として、関数パラメーターをローカル処理変数として使用することはありません。つまり、関数パラメーターを読み取り専用として扱います。

    私の考えでは、直感的に理解できるコードは保守性にとって最も重要であり、ローカル処理変数として使用するように関数パラメーターを変更すると、その目標に反する傾向があります。メソッドの中央と下部で、パラメーターの値が上部と同じになることを期待するようになりました。 さらに、適切な名前のローカル処理変数を使用すると、理解しやすくなる場合があります。

    それでも、@ Stewartが言うように、このルールは関数の長さと複雑さに応じて多かれ少なかれ重要です。表示されているような短く単純な関数の場合、新しいローカル変数(非常に主観的な)を導入するよりも、パラメーター自体を使用する方が理解しやすい場合があります。

    それでも、のように単純なものを作成する場合は、ローカル処理の一部としてパラメーターを変更する代わりに、ローカル処理変数countDigits()を使用する傾向があります。remainingBalancenum

  2. メソッドの先頭でローカルパラメーターを変更して、パラメーターを正規化する場合があります

    void saveName(String name) {
      name = (name != null ? name.trim() : "");
      ...
    }
    

    私はこれが大丈夫だと合理化します:

    a。メソッドの上部で簡単に確認できます。

    b。パラメータは元の概念的な意図を維持し、

    c。パラメータはメソッドの残りの部分で安定しています

    それからまた、半分の時間、私はとにかくローカル変数を使用する傾向がfinalあり、そこにいくつかの余分なを取得するだけです(わかりました、それは悪い理由ですが、私は好きですfinal):

    void saveName(final String name) {
      final String normalizedName = (name != null ? name.trim() : "");
      ...
    }
    
  3. 99%の確率で、コードが関数パラメーターを変更しないままにしている場合(つまり、このコードベースでは、変異パラメーターが直感的でないか予期しない場合)、他の1%の時間で、変異パラメーターに関する簡単なコメントを上部にドロップします。長い/複雑な関数は、理解しやすさに大きな恩恵をもたらす可能性があります。

    int CountDigits(int num) {
        // num is consumed
        int count = 1;
        while (num >= 10) {
            count++;
            num /= 10;
        }
        return count;
    }
    

PS:-)
パラメーターと引数 http://en.wikipedia.org/wiki/Parameter_(computer_science)#Parameters_and_arguments

これらの2つの用語は、大まかに同じ意味で使用されることがあります。特に、「パラメータ」の代わりに「引数」が使用されることがあります。それにもかかわらず、違いがあります。適切に、パラメータはプロシージャ定義に表示されます。引数はプロシージャ呼び出しに表示されます。

それで、

int foo(int bar)

barパラメータです。

int x = 5
int y = foo(x)

の値はxbarパラメーターの引数です。

于 2010-05-02T14:29:47.927 に答える
9

私がこれをするとき、それはいつも私にとって少しおかしいと感じます、しかしそれはそれを避けるために本当に良い理由ではありません。

回避したい理由の1つは、デバッグの目的です。「スクラッチパッド」変数と関数への入力の違いがわかると、デバッグの途中で非常に役立ちます。

私の経験では、これが頻繁に発生するものとは言えません。名前を変えるためだけに別の変数を導入する価値があることがよくありますが、それ以外の場合は最もクリーンなコードが値を変更することになります。変数の、それならそうです。

これが発生して完全に合理的な状況の1つは、「デフォルトを使用する」という意味の値(通常、JavaやC#などの言語でのnull参照)がある場合です。その場合、パラメータの値を「実際の」デフォルト値に変更することは完全に合理的だと思います。これは、オプションのパラメーターを持つことができるC#4で特に役立ちますが、デフォルト値は定数である必要があります。

例えば:

public static void WriteText(string file, string text, Encoding encoding = null)
{
    // Null means "use the default" which we would document to be UTF-8
    encoding = encoding ?? Encoding.UTF8;
    // Rest of code here
}
于 2010-05-02T12:58:43.493 に答える
5

CおよびC++について

私の意見では、パラメーターはすでにローカル変数であるため、関数のローカル変数として使用することは問題ありませんでは、それをそのまま使用しないのはなぜですか?

変更可能な変数を操作するためだけにパラメーターを新しいローカル変数にコピーするときも、私はばかげていると感じます。

しかし、これはかなり個人的な意見だと思います。好きなようにしてください。これだけでパラメータをコピーするのが苦手な場合は、あなたの性格がそれを気に入らないことを示しているので、それを行うべきではありません。

于 2011-02-26T07:46:41.900 に答える
1

元の値のコピーが必要ない場合は、新しい変数を宣言しません。

IMOパラメータ値を変更することは、一般的に悪い習慣ではないと思い
ます。それは、コードでどのように使用するかによって異なります。

于 2010-05-02T13:19:31.513 に答える
0

私のチームのコーディング標準では、手に負えなくなる可能性があるため、これを推奨していません。あなたが見せているような機能については、誰もが何が起こっているのかを見ることができるので、それは害にはなりません。問題は、時間とともに関数が長くなり、バグ修正が行われることです。関数がコードでいっぱいの複数の画面になるとすぐに、これは混乱し始めます。それが私たちのコーディング標準がそれを禁止している理由です。

コンパイラーは冗長変数を非常に簡単に取り除くことができるはずなので、効率に影響はありません。これが問題ないかどうかは、おそらくあなたとあなたのコードレビューアの間だけです。

于 2010-05-02T12:57:42.427 に答える
0

通常、関数内のパラメーター値は変更しません。関数の後半のある時点で元の値を参照する必要がある場合でも、元の値があります。単純なケースでは問題ありませんが、後でコードを追加すると、変更されていることに気付かずに「num」を参照する可能性があります。

于 2010-05-02T12:58:40.083 に答える
0

コードは可能な限り自給自足である必要があります。つまり、アルゴリズムの一部として渡されるものに依存するようになりました。チームの別のメンバーがこれを参照によるパスに変更することを決定した場合、大きな問題が発生する可能性があります。

インバウンドパラメータが不変であると予想される場合は、インバウンドパラメータをコピーすることをお勧めします。

于 2010-05-02T15:14:48.617 に答える
0

ポインターでない限り、私は通常、関数パラメーターを変更しません。ポインターである場合は、ポイントされている値を変更する可能性があります。

于 2010-05-02T15:28:09.707 に答える
0

これのベストプラクティスは言語によって異なると思います。たとえば、Perlでは、任意の変数または変数の一部をローカルスコープにローカライズできるため、そのスコープ内で変数を変更しても、そのスコープ外では何の影響もありません。

sub my_function
{
    my ($arg1, $arg2) = @_;    # get the local variables off the stack

    local $arg1;    # changing $arg1 here will not be visible outside this scope
    $arg1++;

    local $arg2->{key1};   # only the key1 portion of the hashref referenced by $arg2 is localized
    $arg2->{key1}->{key2} = 'foo';   # this change is not visible outside the function

}

関数内で変更した関数への参照によって渡されたデータ構造をローカライズするのを忘れて、ときどき噛まれました。逆に、複数のシステム間で共有された関数の結果としてデータ構造を返した後、呼び出し元が誤ってデータを変更し、通常は遠隔作用と呼ばれる追跡が困難な問題でこれらの他のシステムに影響を与えました。ここで行う最善の方法は、データを返す前にデータのクローンを作成するか*、または読み取り専用**にすることです。

* Perlではdclone()、組み込みのStorableモジュールの関数を参照してください。
** Perlでは、 lock_hash()またはlock_hash_ref()組み込みのHash::Utilモジュールを参照してください。

于 2010-05-02T16:42:16.680 に答える