Delphi: Все константы постоянны, но некоторые из них более постоянные, чем другие?
Рассмотрим:
const
clHotlight: TColor = $00FF9933;
clLink = clHotLight; //alias of clHotlight
[Error] file.pas: Constant expression expected
и альтернативная формулировка, которая работает:
const
clHotlight = TColor($00FF9933);
clLink = clHotLight; //alias of clHotlight
Поясните.
Тогда рассмотрим:
const
AdministratorGUID: TGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
SuperuserGUID = AdministratorGUID; //alias of AdministratorGUID
[Error] file.pas: Constant expression expected
И исправить.
Изменить: добавлено ключевое слово const
перед объявлениями; кто-то не верил, что они были const.
Ответы
Ответ 1
clHotlight: TColor = $00FF9933;
не является константой, а типизированной константой (= статическая переменная), то есть компилятор резервирует слот в памяти для TColor, который сначала будет хранить значение $00FF9933
во время выполнения.
Поскольку это значение может быть изменено позже (с опцией Assignable Const ON), он не является реальной константой и не может быть принят компилятором в clLink = clHotLight;
clHotlight = TColor($00FF9933);
строго совпадает с clHotlight = $00FF9933;
Это истинная константа, и компилятор заменит clHotlight
на ее значение $00FF9933
, где бы он ни появлялся в коде. И для clLink
.
Прочитайте этот вопрос SO ( В Delphi 7, почему я могу назначить значение const?) и все хорошие ответы там...
EDIT: о TGUID...
Проблема в том, что запись AdministratorGUID: TGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
не является правильной.
Для вызова StringToGUID
за сценой используется магия компилятора, что позволяет выразить GUID как строку, которая по своей природе не является. Это записи.
Итак, попытка AdministratorGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
не будет работать. Это не GUID...
Обходным решением является наличие типизированных константных и переменных, указывающих на одну и ту же область памяти с помощью директивы absolute
:
const
AdministratorGUID: TGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
var
SuperuserGUID: TGUID absolute AdministratorGUID; //alias of AdministratorGUID
RootGUID: TGUID absolute AdministratorGUID; //alias of AdministratorGUID
Ответ 2
Я пробовал этот код:
const
CAnswer1 = 42;
CAnswer2 : Integer = 42;
var
LAnswer : Integer;
begin
LAnswer := CAnswer1;
LAnswer := CAnswer2;
end;
и здесь приведен код:
Project9.dpr.18: LAnswer := CAnswer1;
004101AC C7056C6E41002A00 mov [$00416e6c],$0000002a //<- assign a hard-coded "42" value
Project9.dpr.19: LAnswer := CAnswer2;
004101B6 A1701C4100 mov eax,[$00411c70] //<- fetch a variable content
004101BB A36C6E4100 mov [$00416e6c],eax //<- assign this content
Вы правы: некоторые константы более постоянные, чем другие.
Вторая константа фактически обрабатывается компилятором как переменная.
Ответ 3
clHotlight: TColor = $00FF9933;
^
Объявляет clHotlight
как "переменную" (ну, ok "назначаемая константа", если вы разрешили это в параметрах компилятора) с помощью :
.
Как вы нашли, объявив:
clHotlight = TColor($00FF9933);
Не выделяет clHotlight
, пока он не будет указан позже.
То же самое относится к вашему GUID.
Ответ 4
Проблема возникает из-за того, что типизированная константа не является, поистине, константой, как было объяснено с различной степенью ясности и успеха другими.
То, что пока еще не показано, - это то, как обойти проблему (в большом числе случаев), хотя пара была мучительно близка к отказу от этой тайны...:)
В вашем конкретном случае вы можете обойти проблему, изменив "сглаживание" значения и типизированного объявления константы следующим образом:
const
clLink = $00FF9933;
clHotlight: TColor = clLink;
clLink теперь предоставляет вашу истинную константу, а clHotlight - типизированная константа с таким же значением, как clLink.
Для GUID можно использовать один и тот же метод, но вы должны иметь в виду нормальное постоянное выражение, используемое для инициализации типизированной константы GUID - оно не использует запись, а просто литеральную строку, поэтому:
const
ID_CONSTANT = '{AA1C8AF2-C290-40AB-9CF5-2888A46E1660}';
GUID_CONSTANT: TGUID = ID_CONSTANT;
ПРИМЕЧАНИЕ.. Такие константы GUID прекрасно используются во всех местах, где требуется TGUID, например. IsEqualGUID (tguid, GUID_CONSTANT) и т.д.
Ответ 5
Прочтите здесь Понимание типизированных констант в Delphi
Ответ 6
Правая часть объявления константы должна быть "константным выражением", которое определяется как "константное выражение - это выражение, которое компилятор может оценить без выполнения программы, в которой он встречается". Вы можете найти весь принятый синтаксис для постоянного выражения в руководстве по языку.
Обратите внимание, что в руководстве по языку явно указано, что "типизированные константы не могут встречаться в постоянных выражениях". - и почему ваши объявления терпят неудачу, оба clHotlight: TColor = $00FF9933; и AdministratorGUID: TGUID =...; являются типизированными константами.
Кроме того, постоянное выражение не может включать вызовы функций, кроме тех, которые перечислены в руководстве по языку (т.е. Length(), SizeOf() и некоторые другие), которые компилятор может вычислить во время компиляции.
Перепишите этот путь:
const
AdminGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
AdministratorGUID: TGUID = AdminGUID;
SuperuserGUID: TGUID = AdminGUID;
И он будет работать.
Ответ 7
Добро пожаловать в эволюцию Delphi. в delphi 1 и 2 вы не можете назначить начальное значение константы глобальному var (ex: var xVar: Integer = 1). Единственный способ, которым вы можете это сделать, - использовать const xVar: Integer = 1) и некоторые, где в ваших кодах, вы можете при необходимости изменить его на что-нибудь. Пока они не избавятся от этой древней особенности, вы не можете использовать конструкцию const xVar: Integer как значение const.
Приветствия
Фам