enum против неизменяемого в D - PullRequest
13 голосов
/ 25 января 2011

Какая разница между

enum i = 2;
enum s = "Hello";

и

immutable i = 2;
immutable s = "Hello";

в D 2.0?

Ответы [ 2 ]

23 голосов
/ 25 января 2011

enum - это пользовательский тип, а не переменная. enum e = 2; - это сокращение для чего-то вроде этого enum : int { e = 2 } (то есть аноним enum с одним членом e), см. документацию . По определению все члены анонимного перечисления помещаются в текущий объем. Итак, e - это член типа, помещенный в текущую область видимости, где он ведет себя как буквальный . immutable i = 2;, с другой стороны, фактически создает переменную i типа int.

Эта разница имеет пару последствий:

  • enum e не будет иметь ни места в памяти, ни адреса (это не lvalue), так как ни тип, ни его члены не имеют адреса. То есть ты не можешь что-то сделать как auto ptr = &e; (так же, как вы не можете auto ptr = &2;). immutable i, с другой стороны, является нормальной переменной (просто неизменной).
  • Как обсуждал Джонатан , неизменяемые переменные могут быть инициализированы во время компиляции или во время выполнения, тогда как тип (со всеми его членами, определяющими тип) должен быть известен в время компиляции.
  • Компилятор может просто заменить все появления e на 2. Для i это обычно требуется создать область памяти (хотя оптимизирующий компилятор может быть в состоянии избежать этого иногда). По этой причине рабочая нагрузка во время можно ожидать, что компиляция для enum будет несколько ниже, а бинарный несколько меньше.
  • Существует неожиданная разница для массивов. Для enum uint[2] E = [0, 1]; и immutable uint[2] I = [0, 1]; доступ к enum, например, E[0], банка быть на порядки медленнее, чем для массива immutable, например I[0], тем более что массивы E и I становятся больше. Это так потому что для immutable массив, это просто обычный поиск в массиве, скажем, глобальный переменная. Для enum однако похоже, что массив создается каждый раз время, прежде чем оно привыкнет, например, внутри функции для глобального enum (не спросите меня, почему, но компилятор действительно, кажется, просто заменяет внешний вид со значением в этом случае тоже). Я никогда не пробовал, но догадался бы, что то же самое относится к enum строкам и другим нетривиальным типам.

Подводя итог: когда я использую константы времени компиляции, я обычно беру enum, если только эти константы являются массивами, или мне нужна память по какой-то другой причине.

8 голосов
/ 25 января 2011

перечисления всегда инициализируются во время компиляции. Таким образом, им должны быть присвоенные значения, которые могут быть созданы с помощью CTFE (Оценка функции времени компиляции).

неизменяемые переменные могут быть инициализированы во время выполнения. Если неизменяемая переменная имеет глобальное время жизни (так что это переменные модуля, статический класс или статическая локальная переменная), то ее необходимо инициализировать во время компиляции или во время выполнения с помощью статического конструктора (хотя статические локальные переменные не могут назначаться статическим конструктором). Если неизменяемая переменная является нестатической локальной переменной, то она инициализируется во время выполнения (хотя, если значение является константой, компилятор может оптимизировать ее и инициализировать во время компиляции). Таким образом, вы можете создавать неизменяемые локальные переменные во время выполнения, в отличие от перечислений.

РЕДАКТИРОВАТЬ: Еще один случай, который я забыл: неизменяемые переменные-члены должны быть либо инициализированы непосредственно с помощью CTFE, либо инициализированы с помощью неизменяемого конструктора. Если неизменяемая переменная-член инициализируется непосредственно с помощью CTFE, то, очевидно, это делается во время компиляции, тогда как инициализация его в неизменяемом конструкторе выполняется во время выполнения.

...