如果我编译下面的代码,它会在第1行发出警告:
分配给lTime的值从未使用*
但如果删除该行,我会在第2行收到不同的警告:
变量lTime可能尚未初始化
编译器是否缺少某些内容,或者是我?
procedure TFormWebServices.RemoveOldReports;
var
TSR : TSearchRec;
I : Integer;
lCutOff,
lTime : Int64;
TSToDelete: TStringList;
S,Msg : String;
E : Exception;
begin
lCutOff := DelphiToJavaDateTime(Now - cDefReportLifeMins/1440);
I := FindFirst(FReportDir + '*.pdf',0,TSR);
TSToDelete := TStringList.Create;
while I = 0 do
begin
if (TSR.Attr and faDirectory) = 0 then
begin
lTime := lCutOff; // Line 1
try
lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1));
except
on E:Exception do lTime := lCutOff;
end;
if lTime < lCutOff then // Line 2
TSToDelete.Add(TSR.Name);
end;
I := FindNext(TSR);
end;
这不是Why is the Compiler warning that variable may not be initialized?的欺骗,因为我也在例外中指定lTime
。
答案 0 :(得分:7)
lTime := lCutOff;
try
lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1));
except
on E:Exception do lTime := lCutOff;
end;
if lTime < lCutOff then
TSToDelete.Add(TSR.Name);
编译器警告此代码是正确的。在第一行分配lTime := lCutOff
时,永远不会读取该分配中写入的值。
但是,当您删除代码时,事情就不那么明确了。
try
lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1));
except
on E:Exception do lTime := lCutOff;
end;
if lTime < lCutOff then
TSToDelete.Add(TSR.Name);
有两种情况需要考虑:try/except
块内未引发异常,或者引发异常。
如果没有引发异常,那么很简单,lTime
被赋予StrToInt64
的结果,因此在被读取之前被初始化。
在引发异常时,lTime
未在块内初始化。接下来会发生什么?
Exception
(非强制性),则会被捕获并初始化lTime
。Exception
,那么它就不会被捕获,并且永远不会读取lTime
。因此,编译器可以推断所有这些,因此不会发出未初始化的变量警告。但是,遗憾的是,编译器不会对这种复杂性进行流程分析。我相信它的逻辑运行如下:
lTime
初始化之前引发异常,然后lTime
,但仍然可能未初始化。在第2步中,它应该能够意识到lTime
已初始化,但它根本不执行此类分析。因此,虽然有人可能会认为编译器可以做得更好,但您必须接受这一点作为其分析算法的限制。
了解到我们的任务是找到编写代码的方法并避免警告。我们不想压制警告,我们只需要找到一种方法来编写代码,使其既正确又无警告。
在我看来,前进的方向是认识到异常是在这里使用的错误工具。此转换失败是正常行为。您应该使用转换函数编写代码,这些函数在失败时不会引发异常。例如,您可以使用以下选项之一:
if TryStrToInt64(..., lTime) then
if lTime < lCutOff then
....
else
lTime := lCutoff;
或者:
lTime := StrToInt64Def(..., lCutoff);
if lTime < lCutOff then
....
答案 1 :(得分:-1)
这是正确的行为。第1行的值永远不会被使用,因为在try / except中你分配一个新的值而不使用前一个值,因此警告。
如果删除该行,则尝试在try / except块之外使用lTime变量,该变量可能会失败,而不会将值实际设置为lTime
procedure TFormWebServices.RemoveOldReports;
var
TSR : TSearchRec;
I : Integer;
lCutOff,
lTime : Int64;
TSToDelete: TStringList;
S,Msg : String;
E : Exception;
begin
lCutOff := DelphiToJavaDateTime(Now - cDefReportLifeMins/1440);
I := FindFirst(FReportDir + '*.pdf',0,TSR);
TSToDelete := TStringList.Create;
while I = 0 do
begin
if (TSR.Attr and faDirectory) = 0 then
begin
lTime := lCutOff; // Line 1
try
lTime := StrToInt64(Copy(TSR.Name,1,pos('.',TSR.Name)-1));
except
on E:Exception do lTime := lCutOff;
end;
if lTime < lCutOff then // Line 2
TSToDelete.Add(TSR.Name);
end;
I := FindNext(TSR);
end;
你可以这样做
procedure TFormWebServices.RemoveOldReports;
var
TSR : TSearchRec;
I : Integer;
lCutOff,
lTime : Int64;
TSToDelete: TStringList;
S,Msg : String;
E : Exception;
begin
lCutOff := DelphiToJavaDateTime(Now - cDefReportLifeMins/1440);
I := FindFirst(FReportDir + '*.pdf',0,TSR);
TSToDelete := TStringList.Create;
while I = 0 do
begin
if (TSR.Attr and faDirectory) = 0 then
begin
lTime := StrToInt64Def(Copy(TSR.Name,1,pos('.',TSR.Name)-1), lCutOff);
if lTime < lCutOff then
TSToDelete.Add(TSR.Name);
end;
I := FindNext(TSR);
end;