Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Можно ли инициализировать несколько переменных некоторого типа в одной строке?

Автор вопроса: Edijs KolesnikovičsОтветов: 4

Я пытался писать как можно меньше кода. Итак, я использую:

MyBoolean := Memo1.Text <> '';

вместо

if Memo1.Text = '' then
  MyBoolean := true
else
  MyBoolean := false;

Объявить и инициализировать

var
  myGlobal: integer = 99;

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

int x, y, z;
x=y=z=0;

Спасибо.

  • Ну да и нет. Да для письма, например. X: Integer = 99; Y: Integer = 99; в одной строке, а не в нескольких операторах присваивания. TLama 27.04.2014
  • Это не так много одной строки, если вы используете Ctrl + D (также известное как форматирование кода). Edijs Kolesnikovičs 27.04.2014
  • Да, но нет возможности инициализировать несколько переменных в одном выражении. И я рад, что это так, поскольку такое утверждение, как x=y=z=0, мне довольно трудно читать. Лично я бы написал даже это в несколько строк. TLama 27.04.2014
  • @TLama Почему x=y=z=0 трудно читать или непонятно? Это также стандартная математическая запись, и некоторые языки программирования действительно допускают такой синтаксис. Что, если вместо 0 присваиваемое значение было получено от вызова дорогостоящей (трудоёмкой) функции? Этот синтаксис потребует только одного вызова. Чтобы избежать множественных вызовов в Delphi, вам нужно создать временную переменную, присвоить ей результат функции, а затем иметь несколько строк, присваивающих временное значение переменным. Это было бы если не менее ясно, то уж точно менее изящно. В этом синтаксисе есть. alcalde 27.04.2014
  • Эджис, я восхищаюсь твоей приверженностью DRY (не повторяйся). К сожалению, Delphi имеет тенденцию принимать форму WET (нам нравится печатать или писать все дважды). Существует много синтаксического сахара, который язык не реализует, что может сократить дублированный код, например. тернарный оператор: x, если a else c, множественное присваивание, лучший приоритет оператора (чтобы избежать необходимости в круглых скобках в операторах с логическими операторами), оператор мощности, шаг в цикле for, строки в операторах case, нотация среза, вывод типа и т. д. Я надеюсь, что когда они перейдут на. alcalde 28.04.2014
  • @alcalde, почему? Я не знаю. Может быть, потому что, когда я что-то читаю, мой мозг обычно меньше сосредотачивается на том, что находится в середине выражения. Так что, может быть, я боюсь потерять эти переменные y и z при чтении, я не знаю. А насчет временных переменных, что с ними не так? Я скорее буду четко видеть написанное, чем бояться лишнего задания. Кроме того, в сгенерированном ассемблерном коде будет то же самое. Или вы думаете, что есть одна инструкция, которая будет присваивать возвращаемое значение функции сразу трем переменным? TLama 28.04.2014

variablesinitializationdelphi

Ответы

Ответ 1 · рейтинг 5 · David Heffernan

Вы можете инициализировать только одну локальную переменную для каждого оператора.

Ответ 2 · рейтинг 6 · kludg

В C присваивание представляет собой выражение (возвращает значение).

В Паскале присваивание представляет собой инструкцию (не возвращает значение).

Разница имеет некоторые интересные последствия. Например, в C оба

while (x=0)

а также

while (x==0)

являются синтаксически допустимыми конструкциями (это источник бесчисленных ошибок), в то время как в Паскале

while (x:=0)

является синтаксически недопустимым, поскольку x:=0 является оператором.

Ответ 3 · dummzeuch

Конечно, можно было бы написать функцию

function AssignInteger(var _AssignTo: integer; _Value: integer): integer;
begin
  Result := _Value;
  _AssignTo := _Value;
end;

и используйте его так:

var
  i, j, k: integer;
begin
  i := AssignInteger(j, AssignInteger(k, 5));

Но это не совсем то, что вы хотите, говоря, что вы хотите написать как можно более короткий код.

Я указываю это, тем не менее, на всякий случай.

Ответ 4 · Disillusioned

Как говорит dummzeuch, вы можете написать свою собственную процедуру. Однако я бы предпочел вариант с подписью типа: procedure AssignIntegers(AValue, ATargetArray);. И в идеале вызовите процедуру с помощью: AssignInteger(99, [X, Y, Z]);.

К сожалению, идеальный вариант не работает, но следующая процедура достаточно близка и должна быть достаточной. Он работает, беря указатели на целые числа, которые необходимо присвоить.

procedure AssignIntegers(AValue: Integer; const ATargets: array of PInteger);
var
  I: Integer;
begin
  for I := Low(ATargets) to High(ATargets) do
    ATargets[I]^ := AValue;
end;

Следующий тестовый пример DUnit демонстрирует, что он работает. Вы даже можете держать под рукой массив этих целочисленных указателей, чтобы переназначить их в любое время.

type
  TArrayPInteger = array of PInteger;
procedure TDelphiTests.TestAssignIntegers;
var
  X,Y,Z: Integer;
  LGroup: TArrayPInteger;
begin
  AssignIntegers(1, [@X, @Y, @Z]); { Pass open arrray using addresses of integers to initialise }
  CheckEquals(1, X);
  CheckEquals(1, Y);
  CheckEquals(1, Z);

  LGroup := TArrayPInteger.Create(@X, @Y); { Handy technique to initialise dynamic arrays }
  AssignIntegers(2, LGroup);
  CheckEquals(2, X);
  CheckEquals(2, Y);
  CheckEquals(1, Z); { Not part of group }
end;

Предупреждение

Единственным реальным недостатком является то, что вы теряете проверку типов. Компилятор не помешает вам передать адрес нецелочисленных типов. Это может привести к повреждению данных других структур или нарушению прав доступа.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы