Избежание «переменная не могла быть инициализирована» - PullRequest
12 голосов
/ 27 апреля 2010

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

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; в начало процедуры, но мне интересно, не может ли быть лучшего способа структурировать это, чтобы избежать проблемы. У кого-нибудь есть идеи?

Ответы [ 5 ]

11 голосов
/ 27 апреля 2010

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

6 голосов
/ 27 апреля 2010

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

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 , но также проясняет, что инициализация локальной переменной должна быть перенесена в условную ветвь, то есть то, что обращается к предупреждение компилятора (которое выдается только в том случае, если переменная используется в ветви, где она не может быть инициализирована - в ветви, которая ее вообще не использует, такое предупреждение не выдается, а в ветви, где она используется, она наверняка быть инициализированным, и так как используется в одной ветви, вы также не получите подсказку "может не использоваться".

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

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

6 голосов
/ 27 апреля 2010

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

1 голос
/ 27 апреля 2010

я бы изменил начало вашей процедуры на

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

1 голос
/ 27 апреля 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...