#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;