Как сделать так, чтобы переменная локального массива условно указывала на параметр открытого массива?

#arrays #delphi #delphi-xe7

Вопрос:

Я пытаюсь условно назначить локальную переменную открытого массива, чтобы она указывала на параметр открытого массива const:

 uses  System.Generics.Collections,  System.Generics.Defaults;   type  TArray = class(System.Generics.Collections.TArray)  public  class function SameValueslt;Tgt;(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparerlt;Tgt;; AOrderMatters : Boolean = True) : Boolean; overload; static;  end;   ...   class function TArray.SameValueslt;Tgt;(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparerlt;Tgt;; AOrderMatters : Boolean = True) : Boolean; var  ArrA : TArraylt;Tgt;;  ArrB : TArraylt;Tgt;;  i : integer; begin  //checking sizes  if(Length(AValuesA) lt;gt; Length(AValuesB)) then  begin  Result := False;  Exit;  end;   if(AOrderMatters) then  begin  //I don't need to change the arrays, so I could directly point to the open array parameters  ArrA := AValuesA;  ArrB := AValuesB;  end else  begin  //copying to local arrays  SetLength(ArrA, Length(AValuesA));  TArray.Copylt;Tgt;(AValuesA, ArrA, Length(AValuesA));  SetLength(ArrB, Length(AValuesB));  TArray.Copylt;Tgt;(AValuesB, ArrB, Length(AValuesB));   //sorting local arrays  TArray.Sortlt;Tgt;(ArrA);  TArray.Sortlt;Tgt;(ArrB);  end;   //comparing elements  i := 0;  while(i lt; Length(ArrA)) do  begin  if(not AComparer.Equals(ArrA[i], ArrB[i])) then  begin  Result := False;  Exit;  end;  Inc(i);  end;  Result := True; end;  

При компиляции возникает ошибка E2010 при:

 //I don't need to change the arrays, so I could directly point to the open array parameters ArrA := AValuesA; ArrB := AValuesB;  

E2010 Несовместимые типы: «Динамический массив» и «массив T»

Я попробовал следующее:

 ArrA := @AValuesA; ArrB := @AValuesB;  

Он компилируется, но затем вызывает исключение AV во время выполнения (и, прежде всего, я не знаю, будет ли это безопасным подходом).

Вот мой код тестового приложения:

 uses  System.Generics.Defaults;  procedure TForm1.FormCreate(Sender: TObject); var  ArrA : array of string;  ArrB : array of string; begin  SetLength(ArrA, 2);  ArrA[0] := 'hello';  ArrA[1] := 'world';   SetLength(ArrB, 2);  ArrB[0] := 'world';  ArrB[1] := 'hello';   if(TArray.SameValueslt;stringgt;(ArrA, ArrB, TEqualityComparerlt;stringgt;.Default, True)) then  ShowMessage('Same values and same order')  else if(TArray.SameValueslt;stringgt;(ArrA, ArrB, TEqualityComparerlt;stringgt;.Default, False)) then  ShowMessage('Same values but different order')  else  ShowMessage('Different values'); end;  

Комментарии:

1. Вы не можете этого сделать, эти типы просто несовместимы. Метаданные динамического массива (т. е. количество ссылок и длина) являются частью самого объекта, но для открытого массива его метаданные (только длина) передаются функции в качестве отдельного параметра.

2. О! Это так неудобно! Я буду выполнять две отдельные функции… Спасибо

3. Вы можете сделать это достаточно легко в одной функции. Вы просто создаете копии, сортируете их, а затем снова рекурсивно вызываете ту же функцию, но передаете True AOrderMatters ее . Я напишу ответ, чтобы показать, как это сделать.

4. Да, это, безусловно, был бы более чистый код, но я беспокоился о производительности и старался избегать копирования целых массивов, если это не было строго необходимо

5. Вам нужно скопировать массивы, если вы собираетесь сортировать, но если вам не нужно сортировать, то вы можете избежать копирования, как я описал, и как показывает мой ответ.

Ответ №1:

То, что вы пытаетесь сделать, невозможно, потому что открытые массивы и динамические массивы несовместимы так, как пытается сделать ваш код.

Однако есть простой способ достичь того, чего вы хотите, используя простую рекурсию. Подобный этому:

 class function TArray.SameValueslt;Tgt;(const AValuesA: array of T; AValuesB: array of T; const AComparer: IEqualityComparerlt;Tgt;; AOrderMatters : Boolean = True) : Boolean; var  ArrA : TArraylt;Tgt;;  ArrB : TArraylt;Tgt;;  i : integer; begin  //checking sizes  if Length(AValuesA) lt;gt; Length(AValuesB) then  begin  Result := False;  Exit;  end;   if not AOrderMatters then  begin  //copying to local arrays  SetLength(ArrA, Length(AValuesA));  TArray.Copylt;Tgt;(AValuesA, ArrA, Length(AValuesA));  SetLength(ArrB, Length(AValuesB));  TArray.Copylt;Tgt;(AValuesB, ArrB, Length(AValuesB));   //sorting local arrays  TArray.Sortlt;Tgt;(ArrA);  TArray.Sortlt;Tgt;(ArrB);   Result := SameValueslt;Tgt;(ArrA, ArrB, AComparer, True);  Exit;  end;   //comparing elements  for i := 0 to High(AValuesA) do  begin  if not AComparer.Equals(AValuesA[i], AValuesB[i]) then  begin  Result := False;  Exit;  end;  end;   Result := True; end;