在第一个代码块中注释的两个部分看似相同但产生不同的结果(由于其他地方的问题)。我不明白他们是如何不同的。我唯一要改变的是注释掉第一部分(for循环)或第二部分(赋值行)并获得不同的结果。
var
Amount: Integer;
I: Integer;
begin
Amount := 3;
// This produces undesired results (**the for loop**)
for I := 0 to Amount-1 do
CharDataBool[I] := CharToArray(CharDataText[I]);
// This works as expected (**the assignment lines**)
CharDataBool[0] := CharToArray(CharDataText[0]);
CharDataBool[1] := CharToArray(CharDataText[1]);
CharDataBool[2] := CharToArray(CharDataText[2]);
下面的代码有可疑的做法,在某种程度上是问题的根源,但我的问题是关于上面的代码。上面的问题只有在CharToArray函数留下false未分配时才会显示,如下所示:
function CharToArray(Source: TCharDetails): TCharArray;
var
X, Y: Integer;
begin
SetLength(Result, Source.Width, 10);
for Y := 0 to 9 do
for X := 0 to Source.Width-1 do
if Source.S[Y*Source.Width+X] = 'x' then
Result[X,Y] := true
else Result[X,Y] := false; // Adding this solves the problem
end;
在没有进入“离开值未知是真的坏”的情况下,我只想了解为什么问题会出现(for循环)而不是代码的第一部分中的(分配行)?三个赋值行与for循环有何不同?
可以在默认VCL项目中通过Unit1复制以下内容
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
type
TCharArray = array of array of boolean;
TCharDetails = record
S: String;
Width: Integer;
end;
var
CharDataText: array of TCharDetails;
CharDataBool: array of TCharArray;
var
Form1: TForm1;
procedure Init;
implementation
{$R *.dfm}
function CharToArray(Source: TCharDetails): TCharArray;
var
X, Y: Integer;
begin
SetLength(Result, Source.Width, 10);
for Y := 0 to 9 do
for X := 0 to Source.Width-1 do
if Source.S[Y*Source.Width+X] = 'x' then
Result[X,Y] := true;
end;
procedure Init;
var
Amount: Integer;
I: Integer;
X,Y: Integer;
S1, S2: String;
begin
Amount := 2;
SetLength(CharDataText, Amount);
SetLength(CharDataBool, Amount);
ChardataText[0].Width := 10;
ChardataText[0].S :=
// 1234567890
' ' + // 0
' x ' + // 1
' xx ' + // 2
' x ' + // 3
' x ' + // 4
' x ' + // 5
' x ' + // 6
' x ' + // 7
' x ' + // 8
' xxx ';
ChardataText[1].Width := 10;
ChardataText[1].S :=
// 1234567890
'x ' + // 0
' xxxx ' + // 1
' x x ' + // 2
' x ' + // 3
' x ' + // 4
' x ' + // 5
' x ' + // 6
' x ' + // 7
' x ' + // 8
' xxxxxx x';
for I := 0 to Amount-1 do
CharDataBool[I] := CharToArray(CharDataText[I]);
S1 := '';
for Y := 0 to 9 do
for X := 0 to 9 do
S1 := S1 + CharDataBool[1,X,Y].ToString;
CharDataBool[0] := CharToArray(CharDataText[0]);
CharDataBool[1] := CharToArray(CharDataText[1]);
S2 := '';
for Y := 0 to 9 do
for X := 0 to 9 do
S2 := S2 + CharDataBool[1,X,Y].ToString;
// S1 != S2 ??
ShowMessage(S1 + #13 + S2);
end;
initialization
Init;
end.
函数返回值是托管类型。 Result
不保证在进入该功能时重新初始化。
在循环示例中,编译器优化了迭代之间的隐式本地Result
重新初始化。这意味着数组的先前内容仍然存在,必须清除。
作为一般规则,始终初始化=在进入时清除托管函数结果。
在这种情况下,首先在函数中调用SetLength(Result,0,0);
。
有关示例,请参阅Do I need to setLength a dynamic array on initialization?。