Используя аргументы функции как локальные переменные

Что-то вроде этого (да, это не имеет дело с некоторыми пограничными случаями - это не точка):

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

Каково Ваше мнение об этом? Таким образом, с помощью аргументов функции в качестве локальных переменных.
Оба размещаются в стек и в значительной степени идентичную мудрую производительность, я задаюсь вопросом об аспектах лучших практик этого.
Я чувствую себя подобно идиоту, когда я добавляю дополнительную и довольно избыточную строку к той функции, состоящей из int numCopy = num, однако это действительно прослушивает меня.
Что Вы думаете? Этого нужно избежать?

17
задан Greg Hewgill 7 August 2010 в 07:23
поделиться

8 ответов

  1. Как правило, я бы не использовал параметр функции в качестве локальной переменной обработки, т.е. я считаю параметры функции доступными только для чтения.

    На мой взгляд, интуитивно понятный код имеет первостепенное значение для удобства сопровождения, и изменение параметра функции для использования в качестве локальной переменной обработки имеет тенденцию идти вразрез с этой целью. Я ожидал, что параметр будет иметь то же значение в середине и внизу метода, что и вверху. К тому же, метко названная переменная локальной обработки может улучшить понимание.

    Тем не менее, как говорит @Stewart, это правило более или менее важно в зависимости от длины и сложности функции. Для коротких простых функций, подобных показанной вами, простое использование самого параметра может быть проще для понимания, чем введение новой локальной переменной (очень субъективно).

    Тем не менее, если бы мне пришлось написать что-то простое, например countDigits () , я бы предпочел использовать локальную переменную обработки RemainBalance вместо изменения num Параметр как часть локальной обработки - мне кажется более понятным.

  2. Иногда я изменяю локальный параметр в начале метода, чтобы нормализовать параметр:

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

    Я считаю, что это нормально, потому что:

    a. это легко увидеть в верхней части метода

    b. параметр сохраняет свое первоначальное концептуальное намерение, и

    c.параметр стабилен для остальной части метода

    Опять же, в половине случаев я так же склонен использовать локальную переменную в любом случае, просто чтобы получить там пару дополнительных final s (ладно, это плохая причина, но мне нравится final ):

     void saveName (последнее имя строки) {
    final String normalizedName = (name! = null? name.trim ( ): ""); 
     ... 
    } 
     
  3. Если в 99% случаев код оставляет параметры функции неизмененными (т. Е. Изменяющиеся параметры равны неинтуитивно или неожиданно для этой базы кода), затем, в течение оставшегося 1% времени, отбрасывает быстрый комментарий о мутирующем параметре в верхней части длинного / сложная функция может быть большим подспорьем для понимания:

     int CountDigits (int num) {
     // потребляется num 
    int count = 1; 
    while (num> = 10) {
    count ++; 
    num / = 10; 
    } 
    return count; 
    } 
     

PS : -)
параметры против аргументов http://en.wikipedia.org/wiki/Parameter_ (computer_science) #Parameters_and_arguments

Эти два термина иногда используются вольно взаимозаменяемо; в частности, «аргумент» иногда используется вместо «параметра». Тем не менее, разница есть. Правильно, параметры появляются в определениях процедур; аргументы появляются в вызовах процедур.

Итак,

int foo(int bar)

полоса - это параметр.

int x = 5
int y = foo(x)

Значение x является аргументом для параметра bar .

17
ответ дан 30 November 2019 в 12:26
поделиться

Мне всегда кажется немного смешным, когда я это делаю, но это не совсем хорошая причина избегать этого.

Одна из причин, по которой вы могли потенциально захотеть этого избежать, - это цели отладки. Возможность отличить переменные «блокнота» от входных данных функции может быть очень полезной, когда вы на полпути отладки.

Я не могу сказать, что это то, что очень часто всплывает по моему опыту - и часто вы можете обнаружить, что стоит ввести другую переменную только для того, чтобы иметь другое имя , но если код, который в остальном самый чистый, заканчивает тем, что меняет значение переменной, то пусть так и будет.

Одна из ситуаций, когда это может возникнуть и быть вполне разумным, - это когда у вас есть какое-то значение, означающее «использовать значение по умолчанию» (обычно это пустая ссылка на таких языках, как Java или C #). В этом случае я думаю, что вполне разумно изменить значение параметра на «реальное» значение по умолчанию. Это особенно полезно в 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
}
9
ответ дан 30 November 2019 в 12:26
поделиться

Мой стандарт программирования не рекомендует этого делать, потому что это может выйти из-под контроля. На мой взгляд, для такой функции, как та, которую вы показываете, это не повредит, потому что все могут видеть, что происходит. Проблема в том, что со временем функции становятся длиннее, и в них исправляются ошибки. Как только функция занимает более одного экрана с кодом, это начинает сбивать с толку, поэтому наш стандарт кодирования запрещает ее.

Компилятор должен иметь возможность легко избавляться от избыточной переменной, поэтому это не влияет на эффективность. Возможно, это только между вами и вашим рецензентом кода, нормально это или нет.

0
ответ дан 30 November 2019 в 12:26
поделиться

Обычно я бы не стал изменять значение параметра внутри функции. Если в какой-то момент позже в функции вам потребуется обратиться к исходному значению, оно все равно будет у вас. в вашем простом случае проблем нет, но если вы добавите еще код позже, вы можете ссылаться на 'num', не осознавая, что он был изменен.

0
ответ дан 30 November 2019 в 12:26
поделиться

Код должен быть настолько самодостаточным, насколько это возможно. Я имею в виду, что теперь у вас есть зависимость от того, что передается в качестве части вашего алгоритма. Если другой член вашей команды решит изменить это на передачу по ссылке, у вас могут возникнуть большие проблемы.

Лучшей практикой, безусловно, является копирование входящих параметров, если вы ожидаете, что они будут неизменяемыми.

0
ответ дан 30 November 2019 в 12:26
поделиться

Обычно я не изменяю параметры функций, если только они не являются указателями, в этом случае я могу изменить значение, на которое указывают.

0
ответ дан 30 November 2019 в 12:26
поделиться

Если мне не нужна копия исходного значения, я не объявляю новую переменную.

IMO Я не думаю, что изменение значений параметров - плохая практика в целом,
это зависит от того, как вы собираетесь использовать это в своем коде.

1
ответ дан 30 November 2019 в 12:26
поделиться

Я думаю, что передовой опыт зависит от языка.Например, в 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 ).

0
ответ дан 30 November 2019 в 12:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: