Delphi: Все константы постоянны, но некоторые более постоянны, чем другие? - PullRequest
22 голосов
/ 26 апреля 2010

Рассмотрим:

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 перед объявлениями; кто-то не верил, что они были постоянными.

Ответы [ 7 ]

23 голосов
/ 26 апреля 2010

clHotlight: TColor = $00FF9933; - это не константа, а типизированная константа (= статическая переменная), т. Е. Компилятор резервирует слот в памяти для TColor, который будет изначально содержать значение $00FF9933 во время выполнения.
Поскольку это значение может быть изменено позже (с включенной опцией Assignable Const), оно не является реальной константой и не может быть принято компилятором в clLink = clHotLight;

clHotlight = TColor($00FF9933); строго совпадает с clHotlight = $00FF9933;
Это истинная константа, и компилятор заменит clHotlight на его значение $00FF9933, где бы оно ни появилось в коде. И для clLink.

Прочтите этот вопрос SO ( В Delphi 7, почему я могу присвоить значение const? ) и все хорошие ответы там ...

РЕДАКТИРОВАТЬ: о 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
7 голосов
/ 26 апреля 2010

Я попробовал этот код:

  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's content
004101BB A36C6E4100       mov [$00416e6c],eax //<- assign this content 

Вы правы: некоторые константы более постоянны, чем другие. Вторая константа фактически обрабатывается компилятором как переменная.

5 голосов
/ 26 апреля 2010
clHotlight: TColor = $00FF9933; 
          ^

Объявляет clHotlight как ' переменную ' (ну, хорошо, 'назначаемую константу, если вы разрешили это в опциях компилятора) с помощью :.

Как вы обнаружили, объявив:

clHotlight = TColor($00FF9933); 

Не выделяет clHotlight, пока оно не будет указано позже.

То же самое относится и к вашему GUID.

4 голосов
/ 27 апреля 2010

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

Что еще не было показано, так это как работатьвокруг проблемы (в большом количестве случаев), хотя пара очень заманчиво приблизилась к раскрытию этого секрета ...:)

В вашем конкретном случае вы можете обойти проблему, изменив «псевдонимы»значения и объявления типизированной константы следующим образом:

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) и т. д.

3 голосов
/ 26 апреля 2010
2 голосов
/ 27 апреля 2010

Правая часть объявления константы должна быть «константным выражением», которое определяется как «константное выражение - это выражение, которое компилятор может вычислять, не выполняя программу, в которой оно происходит». Вы можете найти полный принятый синтаксис для константного выражения в руководстве по языку. Обратите внимание, что руководство по языку прямо заявляет: «Типизированные константы не могут встречаться в константных выражениях». - и именно поэтому ваши объявления терпят неудачу, оба clHotlight: TColor = $ 00FF9933; и AdministratorGUID: TGUID = ...; набираются константы. Кроме того, константное выражение не может включать вызовы функций, кроме тех, которые перечислены в руководстве по языку (то есть Length (), SizeOf () и некоторые другие), которые компилятор может вычислять во время компиляции. Перепишите так:

const
  AdminGUID = '{DE44EEA0-6712-11D4-ADD4-0006295717DA}';
  AdministratorGUID: TGUID = AdminGUID;
  SuperuserGUID: TGUID = AdminGUID;

И это будет работать.

1 голос
/ 26 апреля 2010

добро пожаловать в эволюцию Delphi. в delphi 1 & 2 нельзя присвоить начальное значение константы глобальному var (например, var xVar: Integer = 1). Единственный способ сделать это - использовать const xVar: Integer = 1) и кое-где, где в ваших кодах, вы можете при желании изменить его на что-то другое. Пока они не избавятся от этой древней функции, вы не можете использовать конструкцию const xVar: Integer в качестве значения const.

Приветствие Фам

...