Как поддерживать хорошую организацию кода, не жертвуя при этом производительностью? - PullRequest
2 голосов
/ 13 января 2011

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

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

В Perl (или, как правило, в зависимости от обстоятельств), есть какие-то изящные методики, позволяющие поместить инициализацию переменной вцикл, но такой, что он инициализируется только при первом проходе?

Я бы подумал о чем-то вроде:

my $variable = undef;
while ($outer_loop) {
    while ($inner_loop) {
       $variable = $variable || 'initial_value'
    }
}

Примечание: подразумевается, что $variable не переназначается внутрицикл.

Теперь, может быть, это я, но это выглядит немного не элегантно.

Итак, вот мой вопрос: есть ли более аккуратный способ сделать это, или мне просто нужно перебить себяи поставить под угрозу организацию кода или поглотить это «не элегантное» решение, описанное выше?

Ответы [ 3 ]

6 голосов
/ 13 января 2011

Для решения проблем в вашем комментарии (переменная вычисляется в функции):

  • Стандартный метод оптимизации такой логики, которую вы хотите, называется memoization (этой функции).Среди других подходов, Perl имеет модуль Memoize, или вы можете сделать это самостоятельно.

      use Memoize;
      memoize('slow_function');
      while ($outer_loop) {
          while ($inner_loop) {
              my $variable = slow_function(arguments);
          }
      }
    
  • Кроме того, если функция всегда выдает 100% одинаковое значение (по проекту) во всемцикл, просто сделайте запоминание плохого человека, инициализируя переменную в операторе до цикла.

    Если у вас есть цикл длиной в 3 страницы (например, такой длинный, что инициализация перед циклом является проблемой читабельности по сравнению с внутренним циклом), у вас есть более серьезная проблема кодирования, чем просто расположение строки инициализациии нужно перефакторировать ваш код в первую очередь.

    В качестве отступления, если ваша единственная забота о размещении переменной перед циклом - это тот факт, что она разрушает контекст читабельности "эта переменная толькодля использования в этом цикле ", вы можете легко решить его:1021 *

  • Или, назвав переменную примерно как my $default_value_for_next_loop = long_func();, и внутри цикла фактически создайте локальную переменную цикла, инициализированную из этого: my $loop_var = $default_value_for_next_loop;

Также, насколько ваш собственный подход ($variable = $variable || 'initial_value';);Я лично нахожу это абсолютно элегантным и читабельным, НО !!!Я почти уверен, что на самом деле он работает на хуже , чем обычный $variable = $default_value_for_next_loop;, потому что вместо прямого присваивания он имеет условный оператор.Но я не могу быть уверен, без бенчмаркинга.

4 голосов
/ 13 января 2011

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

Есть ли это? Вы измерили это? Если ваш $variable применяется к коду в обоих циклах, я бы написал ваш цикл следующим образом:

my $variable = 'initial_value';
while ($outer_loop) {
    while ($inner_loop) {
       # ...
    }
}

Таким образом, читатель знает, что $variable используется в следующем разделе кода, и каково его начальное значение. В вашем фрагменте кода читатель должен найти начальное значение фактическое где-то глубоко в цикле.

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

3 голосов
/ 13 января 2011

Я думаю, что вы слишком далеко зашли к своему руководству. Лучший способ остановить злоупотребление переменной - это отложить ее объявление до того момента, пока она не понадобится. (Таким образом, ограничение его наименьшей возможной лексической областью действия.) Задержка инициализации не предотвращает неправильное использование; это просто создает возможность для кого-то использовать неопределенное значение, выгружать инициализацию своей собственной или использовать вашу переменную для совершенно не связанной цели.

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

my $x = 1;
my $y = f($x);

Задержка инициализации подразумевает отсутствие начального значения. Это хорошо, если его нет или вы не можете определить его заранее, но вы жертвуете ясностью, подкрадываясь к $var //= 'value' позже.

Для переменных, которым необходимо сохранять свое значение на протяжении итераций цикла, вы должны объявлять их вне цикла. Иногда я заключаю циклы в дополнительный блок, чтобы предотвратить попадание этих переменных в следующий код:

{
    my $i = 5;
    for (1 .. 10) {
        say $i++;
    }
}
...