2011-01-13 6 views
2

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

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

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

я думал что-то вроде:

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

NB: Смысл в том, что $variable не переназначены внутри цикла.

Теперь, возможно, это я, но это кажется немного неэлегантным.

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

ответ

6

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

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

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

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

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

    • Имея хорошо документированный код - либо соответствующим образом укажите переменную, либо добавьте комментарий в строку инициализации, либо и то, и другое.

    • Или, называя переменную что-то вроде 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;, потому что он имеет условное выражение вместо прямого назначения. Но я не могу быть уверенным без бенчмаркинга.

+0

Запомните камни, спасибо, что напомнили мне об этом. – Naveed

+0

Спасибо. Я собираюсь обсудить эти варианты и выяснить, какой из них более подходит для моего конкретного модуля ... пища для размышлений. – Dancrumb

4

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

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

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

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

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

+0

Это не просто назначение; значение генерируется посредством вызова функции. Я согласен с тем, что в общих чертах лучше измерить стоимость генерации стоимости и посмотреть, насколько она значительна, но мне все еще интересно узнать, есть ли какие-либо другие методы, которые могут/вообще/быть применены. – Dancrumb

+1

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

3

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

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

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

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

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

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