Подтвердить что ты не робот

Избегание "переменной, возможно, не было инициализировано"

Недавно я столкнулся с процедурой, которая выглядит примерно так:

procedure TMyForm.DoSomething(list: TList<TMyObject>; const flag: boolean);
var
  local: integer;
begin
  if flag then
    //do something
  else local := ExpensiveFunctionCallThatCalculatesSomething;

  //do something else
  for i := 0 to list.Count do
    if flag then
      //do something
    else if list[i].IntValue > local then //WARNING HERE
        //do something else
end;

Это дает Variable 'local' might not have been initialized, хотя вы можете сказать, прочитав код, который вы не ударите по этой строке, если ветвь кода, инициализирующая ее, не запустилась.

Теперь я мог бы избавиться от этого предупреждения, добавив бесполезный local := 0; в начало процедуры, но мне интересно, может быть, нет лучшего способа структурировать это, чтобы избежать проблемы. У кого-нибудь есть идеи?

4b9b3361

Ответ 1

Я бы разделил его на два for-loops - один для флага, когда флаг true, а один для флага - false. В качестве дополнительного преимущества вам не придется выполнять if-инструкцию на каждой итерации.

Ответ 2

IMO, назначение 0 здесь бесполезно - это выгодно для maintanability. Таким образом, вы можете спасти кого-то (возможно, ваше будущее) от необходимости потратить минуту или две, чтобы определить, работает ли код. И умение дизайна, вероятно, будет потеряно на них (даже если это вы!)

Ответ 3

Рефакторинг кода, который содержит два отдельных потока на основе параметра флага:

procedure TMyForm.DoSomething(list: TList<TMyObject>; const flag: boolean);
var
  local: integer;
begin
  if flag then
  begin
    //do something
    //do something else
    for i := 0 to Pred(list.Count) do
      //do something
  end
  else
  begin
    local := ExpensiveFunctionCallThatCalculatesSomething;

    //do something else
    for i := 0 to Pred(list.Count) do
      if list[i].IntValue > local then
        //do something else
  end;
end;

Это существенно повторяет ответ, заданный neilwhitaker1, но также дает понять, что инициализация переменной локальная должна быть введена внутри условной ветки, что является тем, что обращается к предупреждению компилятора (которое испускается только в том случае, если varialbe используется в ветке, где она не может быть инициализирована - в ветке, которая ее вообще не использует, не должно быть выбрано такое предупреждение, а в ветки, где она используется, обязательно будет инициализирована, и поскольку он используется в одной ветке, и вы не получите подсказки "не могут быть использованы".

ПРИМЕЧАНИЕ. Если какое-либо из "//что-то еще" является общим для каждой ветки, они, конечно, могут быть реорганизованы как локальные, вложенные процедуры, чтобы избежать дублирования.

ТАКЖЕ ПРИМЕЧАНИЕ: В приведенном выше коде я скорректировал превышение индекса цикла в цикле for.:)

Ответ 4

добавление локального: = 0 хорошего решения.

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

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

извините за мой плохой английский:)

Ответ 5

i изменил бы верхнюю часть вашей процедуры на

procedure TMyForm.DoSomething(list: TList<TMyObject>; const flag: boolean);
var
  local: integer;
begin
  if flag then
   begin
     local := 0;
     //do something
   end
  else local := ExpensiveFunctionCallThatCalculatesSomething;

и т.д...

Таким образом, Local устанавливается независимо от того, какой флаг, тем более, что он не устанавливается дважды, если флаг false