如何在 Pascal 中输出具有嵌套数组的数组
How to output an array that has nested arrays in Pascal
我正在使用 Pascal 创建音乐播放器的基本概念,但我很难显示其中的专辑。我得到的错误是“(134, 29) 错误:无法读取或写入这种类型的变量”。我假设它是这么说的,因为我在一个数组中使用一个数组,并且很难同时显示两者(尽管我只希望它显示专辑,而不是曲目)。
我的代码如下所示:
function ReadAllTrack(prompt: String): Tracks;
var
i: Integer;
trackArray: Array of Track;
trackCount: Integer;
begin
WriteLn(prompt);
trackCount := ReadIntegerGreaterThan1('Please enter the number of tracks you would like to add: ');
Setlength(trackArray, trackCount);
for i := 0 to trackCount - 1 do
begin
WriteLn('Enter the details for your track:');
trackArray[i] := ReadTrack();
end;
result := trackArray;
end;
function ReadAlbum(): Album;
begin
result.albumName := ReadString('Album name: ');
result.artistName := ReadString('Artist name: ');
result.albumGenre := ReadGenre('Genre:');
result.trackCollection := ReadAllTrack('Track Collection:');
end;
function ReadAllAlbums(): Albums;
var
i: Integer;
albumArray: Array of Album;
albumCount: Integer;
begin
albumCount := ReadIntegerGreaterThan1('Please enter the number of albums you would like to add: ');
Setlength(albumArray, albumCount);
for i := 0 to albumCount - 1 do
begin
WriteLn('Enter the details for your album:');
albumArray[i] := ReadAlbum();
end;
result := albumArray;
end;
procedure DisplayAlbumOptions(listOfAllAlbums: Albums);
var
userInput: Integer;
begin
WriteLn('1. Display all albums');
WriteLn('2. Display all albums for a genre');
userInput := ReadIntegerRange('Please enter a number (1, 2) to select: ', 1, 2);
case userInput of
1: WriteLn(listOfAllAlbums); //Error: Can't read or write variables of this type
end;
end;
基本上,它会要求用户显示 5 个选项:
1.添加相册
2.显示相册
等等
如果用户selects 1,程序会要求用户输入他们想要输入的专辑数量。然后对于每张专辑,它会要求他们输入详细信息,然后是曲目。
然后,如果用户 selects 2,程序将要求用户选择显示现有的每张专辑,或显示单一流派的所有专辑(我将处理这个解决这个问题后)。起初我认为它会像 WriteLn(TheAlbumArray);
一样简单,但结果比我想象的要复杂,因为我认为程序不可能以这种方式显示它。我尝试将专辑和曲目分开,这样它只会在我使用 WriteLn(TheAlbumArray);
时显示专辑,但这是不可能的,因为曲目仍然必须是 "inside" 专辑,这样当我显示专辑时和 select 其中之一,然后它会显示曲目....
对此and/or第二个的任何帮助或建议将不胜感激^^
你原来的问题包含了很多多余的细节。编辑后,您删除了类型声明,但保留了很多多余的细节。
但是,可以看出您将记录数组传递给 Writeln
的问题。 Writeln
函数只能接受某些简单类型作为参数,例如字符串、数值类型、布尔值。您当然不能将数组传递给 Writeln
。您必须遍历数组并单独处理每个成员。
所以你可以试试
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
WriteLn(listOfAllAlbums[i]);
但这也不起作用,因为listOfAllAlbums[i]
是一个记录,而记录是一个复合类型,不能传递给Writeln
。所以需要单独处理记录。如果你只想显示标题,那么你写:
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
WriteLn(listOfAllAlbums[i].albumName);
如果您还想打印曲目标题,则需要遍历记录中包含的数组。
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
begin
WriteLn(listOfAllAlbums[i].albumName);
for j := low(trackCollection) to high(trackCollection) do
WriteLn(listOfAllAlbums[i].trackCollection[j]);
end;
不可能在 Read[ln]
和 Write[ln]
过程中使用复合类型(数组、记录...)。
为了使您的代码更加透明,您可以为数组创建类型助手并使用众所周知的 AsString
属性。这是简单的示例 array of Integer
:
program foo;
{$mode objfpc}{$H+}
{$modeswitch typehelpers}
uses
Classes, SysUtils;
type
TMyArray = array of Integer;
TMyArrayHelper = type helper for TMyArray
private
function GetAsString: string;
procedure SetAsString(const AValue: string);
public
property AsString: string read GetAsString write SetAsString;
end;
function TMyArrayHelper.GetAsString: string;
var
i: Integer;
begin
Result := '';
for i in Self do
begin
if Result <> '' then
Result := Result + ', ';
Result := Result + IntToStr(i);
end;
Result := '[' + Result + ']';
end;
// Relatively simple parser
// Fill free to implement ones for your array type
procedure TMyArrayHelper.SetAsString(const AValue: string);
var
tmp, s: string;
items: TStringArray;
i: Integer;
begin
tmp := Trim(AValue);
if not (tmp.StartsWith('[') and tmp.EndsWith(']')) then
raise Exception.CreateFmt('Invalid array literal format: "%s"', [tmp]);
tmp := tmp.Trim(['[', ']']);
items := tmp.Split([',']);
for s in items do
try
StrToInt(s);
except
on e: Exception do
raise Exception.CreateFmt('Invalid integer literal: "%s"', [s]);
end;
SetLength(Self, Length(items));
for i := 0 to Length(items) - 1 do
Self[i] := StrToInt(items[i]);
end;
var
a1, a2: TMyArray;
begin
a1.AsString := '[1,2,3,5]';
Writeln('a1 = ', a1.AsString);
a2.AsString := a1.AsString;
a2[1] := 999;
Writeln('a2 = ', a2.AsString);
end.
我正在使用 Pascal 创建音乐播放器的基本概念,但我很难显示其中的专辑。我得到的错误是“(134, 29) 错误:无法读取或写入这种类型的变量”。我假设它是这么说的,因为我在一个数组中使用一个数组,并且很难同时显示两者(尽管我只希望它显示专辑,而不是曲目)。
我的代码如下所示:
function ReadAllTrack(prompt: String): Tracks;
var
i: Integer;
trackArray: Array of Track;
trackCount: Integer;
begin
WriteLn(prompt);
trackCount := ReadIntegerGreaterThan1('Please enter the number of tracks you would like to add: ');
Setlength(trackArray, trackCount);
for i := 0 to trackCount - 1 do
begin
WriteLn('Enter the details for your track:');
trackArray[i] := ReadTrack();
end;
result := trackArray;
end;
function ReadAlbum(): Album;
begin
result.albumName := ReadString('Album name: ');
result.artistName := ReadString('Artist name: ');
result.albumGenre := ReadGenre('Genre:');
result.trackCollection := ReadAllTrack('Track Collection:');
end;
function ReadAllAlbums(): Albums;
var
i: Integer;
albumArray: Array of Album;
albumCount: Integer;
begin
albumCount := ReadIntegerGreaterThan1('Please enter the number of albums you would like to add: ');
Setlength(albumArray, albumCount);
for i := 0 to albumCount - 1 do
begin
WriteLn('Enter the details for your album:');
albumArray[i] := ReadAlbum();
end;
result := albumArray;
end;
procedure DisplayAlbumOptions(listOfAllAlbums: Albums);
var
userInput: Integer;
begin
WriteLn('1. Display all albums');
WriteLn('2. Display all albums for a genre');
userInput := ReadIntegerRange('Please enter a number (1, 2) to select: ', 1, 2);
case userInput of
1: WriteLn(listOfAllAlbums); //Error: Can't read or write variables of this type
end;
end;
基本上,它会要求用户显示 5 个选项: 1.添加相册 2.显示相册 等等
如果用户selects 1,程序会要求用户输入他们想要输入的专辑数量。然后对于每张专辑,它会要求他们输入详细信息,然后是曲目。
然后,如果用户 selects 2,程序将要求用户选择显示现有的每张专辑,或显示单一流派的所有专辑(我将处理这个解决这个问题后)。起初我认为它会像 WriteLn(TheAlbumArray);
一样简单,但结果比我想象的要复杂,因为我认为程序不可能以这种方式显示它。我尝试将专辑和曲目分开,这样它只会在我使用 WriteLn(TheAlbumArray);
时显示专辑,但这是不可能的,因为曲目仍然必须是 "inside" 专辑,这样当我显示专辑时和 select 其中之一,然后它会显示曲目....
对此and/or第二个的任何帮助或建议将不胜感激^^
你原来的问题包含了很多多余的细节。编辑后,您删除了类型声明,但保留了很多多余的细节。
但是,可以看出您将记录数组传递给 Writeln
的问题。 Writeln
函数只能接受某些简单类型作为参数,例如字符串、数值类型、布尔值。您当然不能将数组传递给 Writeln
。您必须遍历数组并单独处理每个成员。
所以你可以试试
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
WriteLn(listOfAllAlbums[i]);
但这也不起作用,因为listOfAllAlbums[i]
是一个记录,而记录是一个复合类型,不能传递给Writeln
。所以需要单独处理记录。如果你只想显示标题,那么你写:
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
WriteLn(listOfAllAlbums[i].albumName);
如果您还想打印曲目标题,则需要遍历记录中包含的数组。
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
begin
WriteLn(listOfAllAlbums[i].albumName);
for j := low(trackCollection) to high(trackCollection) do
WriteLn(listOfAllAlbums[i].trackCollection[j]);
end;
不可能在 Read[ln]
和 Write[ln]
过程中使用复合类型(数组、记录...)。
为了使您的代码更加透明,您可以为数组创建类型助手并使用众所周知的 AsString
属性。这是简单的示例 array of Integer
:
program foo;
{$mode objfpc}{$H+}
{$modeswitch typehelpers}
uses
Classes, SysUtils;
type
TMyArray = array of Integer;
TMyArrayHelper = type helper for TMyArray
private
function GetAsString: string;
procedure SetAsString(const AValue: string);
public
property AsString: string read GetAsString write SetAsString;
end;
function TMyArrayHelper.GetAsString: string;
var
i: Integer;
begin
Result := '';
for i in Self do
begin
if Result <> '' then
Result := Result + ', ';
Result := Result + IntToStr(i);
end;
Result := '[' + Result + ']';
end;
// Relatively simple parser
// Fill free to implement ones for your array type
procedure TMyArrayHelper.SetAsString(const AValue: string);
var
tmp, s: string;
items: TStringArray;
i: Integer;
begin
tmp := Trim(AValue);
if not (tmp.StartsWith('[') and tmp.EndsWith(']')) then
raise Exception.CreateFmt('Invalid array literal format: "%s"', [tmp]);
tmp := tmp.Trim(['[', ']']);
items := tmp.Split([',']);
for s in items do
try
StrToInt(s);
except
on e: Exception do
raise Exception.CreateFmt('Invalid integer literal: "%s"', [s]);
end;
SetLength(Self, Length(items));
for i := 0 to Length(items) - 1 do
Self[i] := StrToInt(items[i]);
end;
var
a1, a2: TMyArray;
begin
a1.AsString := '[1,2,3,5]';
Writeln('a1 = ', a1.AsString);
a2.AsString := a1.AsString;
a2[1] := 999;
Writeln('a2 = ', a2.AsString);
end.