如何在 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.