Я недавно натыкался на стандартную программу, которая выглядит примерно так:
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;
наверху процедуры, но интересно, не могло ли быть лучшего способа структурировать это для предотвращения проблемы. У кого-либо есть какие-либо идеи?
Я бы разделил его на два цикла for - один для случая, когда флаг равен true, а другой - когда флаг равен false. В качестве дополнительного преимущества вам не придется выполнять оператор if на каждой итерации.
Выполните рефакторинг кода, чтобы он содержал два отдельных потока на основе параметра flag:
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 , но также дает понять, что инициализация local переменная должна быть перенесена в условную ветвь, что касается предупреждения компилятора (которое выдается только в том случае, если переменная используется в ветке, где она не может быть инициализирована - в ветке, которая ее вообще не использует) должно быть выдано предупреждение, и в той ветке, где оно используется, оно обязательно будет инициализировано, и поскольку оно используется в одной ветке, вы также не получите подсказки «не может использоваться».
ПРИМЕЧАНИЕ: Если какие-либо из «// что-то еще» являются общими для каждой ветви, их, конечно, можно реорганизовать как локальные, вложенные процедуры, чтобы избежать дублирования.
ТАКЖЕ ПРИМЕЧАНИЕ: код выше Я исправил превышение индекса цикла в цикле for. :)
добавление local: = 0 хорошего решения.
как я знаю подсказки, потому что это могут быть неинициализированные переменные. если вы всегда назначаете значения переменных для инициации и используете блоки try finally для проверки ошибок, у вас не будет никаких проблем.
Насколько мне известно, компилятор дает подсказки, потому что даже если вы отметите флаг во время выполнения, ваша переменная может быть не назначена, и ваш код не может работать должным образом.
извините за мой плохой английский :)
ИМО, присвоение 0 здесь не бесполезно - это полезно для удобства обслуживания. Так вы избавите кого-то (возможно, себя в будущем) от необходимости потратить минуту или две на то, чтобы определить, работает ли код. И дизайнерская смекалка им наверняка потеряется (даже если это вы!)
Я бы изменил начало вашей процедуры на
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 устанавливается независимо от того, какой флаг установлен, более того он не устанавливается дважды, если флаг ложный