Я слишком долго держал руки у Дельфи, наверное; За последние пару лет я много занимался Java и PHP. Теперь, когда я вернулся к выполнению небольшой работы Delphi, я понял, что действительно скучаю по условному оператору, который поддерживается как Java, так и PHP.
На сколько мест вы найдете такие строки в своих программах Delphi?
var s : string;
begin
...<here the string result is manipulated>...
if combo.Text='' then
s := 'null'
else
s := QuotedStr(combo.Text);
result := result + s;
end;
где простой
result := result + (combo.text='')?'null':quotedStr(combo.text);
было бы достаточно. Что мне нравится в этом, так это то, что он не только сокращает код, и я также избегаю объявления некоторой вспомогательной переменной s:string
.
Почему условные операторы не являются частью Delphi и - будут ли они когда-либо поддерживаться? Я заметил, что для версии Delphi (generics) 2009 года было сделано несколько языков, поэтому почему бы не добавить эту функцию?
Такой оператор не является частью текущей версии Delphi, поскольку он не был частью предыдущей версии, и спрос был недостаточным, чтобы оправдать затраты на его добавление. (Вы найдете, что это объяснение относится к множеству функций, которые вы хотели бы иметь в большом количестве продуктов.)
Delphi предоставляет набор функций IfThen
в модулях Math и StrUtils, но у них есть неудачное свойство оценки обоих параметров значений, поэтому такой код не будет выполняться:
Foo := IfThen(Obj = nil, '<none>', Obj.Name);
Чтобы все было правильно, нужна помощь от компилятора. В сообществе Delphi я чувствую общую неприязнь к синтаксису C-стиля, используя знак вопроса и двоеточие. Я видел предложения, которые использовали бы синтаксис следующим образом:
Foo := if Obj = nil then
'<none>'
else
Obj.Name;
Часть того, что делает условные операторы настолько привлекательными, заключается в том, что они позволяют писать сжатый код, но стиль Delphi для написания всего делает вышеупомянутое непривлекательным, даже если положить все на одну строку.
Это не обязательно должно быть в форме оператора. Delphi Prism предоставляет компилятор-магическую функцию Iif
, которая оценивает только один из двух параметров:
Foo := Iif(Obj = nil, '<none>', Obj.Name);
Вы спросили, почему такая функция не была бы добавлена вместе со всеми другими языковыми функциями, добавленными в Delphi 2009. Я думаю, что ваша причина. Было много других изменений языка, которые уже требовали деликатной обработки; разработчикам не нужно было обременять еще больше. Особенности не являются бесплатными.
Вы спросили, будет ли у Delphi такая функция. Я не участвую в совещаниях по планированию Эмбаркадеро, и мне пришлось отправить свой хрустальный шар на ремонт, поэтому я не могу сказать наверняка, но я предсказываю, что если бы у него когда-либо была такая особенность, это получилось бы в форме функции Delphi Prism Iif
. Эта идея появляется в конце обсуждение в Quality Central, и делается возражение, что, как новое зарезервированное слово, оно сломается назад совместимость с кодом других людей, который уже определяет функцию с тем же именем. Это не действительный объект, хотя, поскольку он не должен быть зарезервированным словом. Он может быть идентификатором и точно так же, как Writeln
и Exit
, он может быть переопределен в других единицах, даже если тот из системного блока обрабатывается специально.
Ok. Код WTF дня:)
Как получить то, что в основном действует как тройная/условная функция.
program Project107;
{$APPTYPE CONSOLE}
uses SysUtils;
type
TLazyIfThen<T:record>=record
class function IfThen(aCondition:Boolean;aIfTrue, aIfFalse:TFunc<T>):T; static;
end;
class function TLazyIfThen<T>.IfThen(aCondition:Boolean;aIfTrue, aIfFalse:TFunc<T>):T;
begin
if aCondition then
Result := aIfTrue
else
Result := aIfFalse
end;
begin
WriteLn(
TLazyIfThen<Integer>.IfThen(
True,
function:Integer begin result := 0 end,
function:Integer begin result := 1 end
)
);
ReadLn;
end.
Да, это более или менее бесполезно, но это показывает, что это можно сделать.
?:
Чтобы сделать код более компактным . ;)
Существует несколько доступных простых типов дескрипторов для перегруженной функции IFTHEN.
StrUtils.IfThen
(String
)
Math.IfThen
(Integer
)
Math.IfThen
(Int64
)
Math.IfThen
(Double
) (работает и для TDateTime
)
Эта модель падает, как показано в примере, который Андреас прокомментировал, но для простых типов это более чем разумно. Если следует соглашение методов Delphi/Pascal, а не поддаваться методу C использования наименьшего количества символов, насколько это возможно.
Лично я предпочел бы не видеть условный оператор (т.е. ?:
), введенный в Delphi, поскольку я предпочитаю читаемость Delphi/Pascal над C и его производными языками. Я бы предпочел увидеть более инновационные решения типа Delphi для чего-то подобного, чем реализовать больше C-isms.
Здесь есть отчет о контроле качества (8451), который имеет разумное обсуждение.
Поднято в июне 2004 года, и, похоже, от Borland/CodeGear/Embarcadero не было ответа.
В Delphi нет условного оператора, и я серьезно сомневаюсь, что когда-нибудь будет один, но вы никогда не узнаете. Вы всегда можете выдать запрос в Embarcadero.
Альтернативой является определение функции Iff:
function Iff(const ACondition: Boolean; const ATrueValue, AFalseValue: XXX): XXX;
begin
if ACondition then
Result := ATrueValue
else
Result := AFalseValue;
end;
Где XXX - тип желания.
Использовать как:
Result := Result + Iff(combo.text='', 'null', quotedStr(combo.text));
Существует несколько причин, по которым не следует выполнять условный оператор. Одна из них - читаемость. Паскаль (а также Delphi) больше сосредоточен на читабельности, чем языки синтаксиса C, которые в большей степени сосредоточены на мощности символов (как можно больше информации на каждый символ). Условный оператор является мощным, но (по некоторым данным) нечитаемым. Но если вы посмотрите на (страшное) выражение с Delphi... (не нужно больше говорить). Другая причина заключается в том, что условный оператор не требуется. Что является правдой. Но нет необходимости в том, чтобы все еще было реализовано.
В конце концов, это просто вопрос вкуса.
Но если вы хотите оценить только один аргумент, вы всегда можете использовать следующее, что нарушает как читаемость, так и концепцию мощности символов:
[overdesignmode]
// Please don't take this that serious.
type
TFunc = function(): XXX;
function Iff(const ACondition: Boolean; const ATrueFunc, AFalseFunc: TFunc): XXX;
begin
if ACondition then
ATrueFunc
else
AFalseFunc;
end;
[/overdesignmode]
Я бы предпочел, чтобы они выполняли ленивую оценку, и она будет более мощной и может использоваться в разных сценариях. Подробнее см. Ссылку ниже.
http://www.digitalmars.com/d/2.0/lazy-evaluation.html
Приветствия
Другой вариант - использовать generics:
Cond<T> = class
public class function IIF(Cond: boolean; IfVal: T; ElseVal: T): T;
end;
implementation
class function Cond<T>.IIF(Cond: boolean; IfVal, ElseVal: T): T;
begin
if Cond then
Result := IfVal
else
Result := ElseVal;
end;
Это вполне читаемо:
var MyInt: Integer;
begin
MyInt:= Cond<Integer>.IIF(someCondition, 0, 42);
Примечание: как указал Алан Брайант (в 6/21/2004 7:26:21) в QR 8451, это будет всегда оценивайте все 3 аргумента - так что имейте в виду, что это не истинный тернарный оператор.
На самом деле для строк вы можете использовать функцию StrUtils.IfThen:
function IfThen(AValue: Boolean;
const ATrue: string;
AFalse: string = ): string; overload;
Посмотрите в wiki справки delphi: http://docwiki.embarcadero.com/VCL/en/StrUtils.IfThen
Он делает именно то, что вам нужно.
Библиотека кода Jedi (JCL) реализовала трехмерный операнд с набором функций с именем Iff(). См. Здесь документацию:
http://wiki.delphi-jedi.org/wiki/JCL_Help:Iff@Boolean@Boolean@Boolean
Чтобы загрузить JCL, вы можете посетить этот сайт:
?:
.
Еще лучше - перегруженный IIF (inline if), который поддерживает несколько типов данных и результатов.