какая разница между
enum i = 2;
enum s = "Hello";
и
immutable i = 2;
immutable s = "Hello";
in D 2.0?
какая разница между
enum i = 2;
enum s = "Hello";
и
immutable i = 2;
immutable s = "Hello";
in D 2.0?
enum
— это пользовательский тип, а не переменная. enum e = 2;
— это сокращение для чего-то вроде этого enum : int { e = 2 }
(т. е. анонимного перечисления с одним элементом 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
, если только эти константы не являются массивами или мне не нужна ячейка памяти по какой-то другой причине.
перечисления всегда инициализируются во время компиляции. Таким образом, им должны присваиваться значения, которые можно создать с помощью CTFE (оценка функции времени компиляции).
неизменяемые переменные могут быть инициализированы во время выполнения. Если неизменяемая переменная имеет глобальное время жизни (то есть переменные модуля, статический класс или статическая локальная переменная), то она должна быть либо инициализирована во время компиляции, либо во время выполнения с помощью статического конструктора (хотя статические локальные переменные не могут быть назначен статическим конструктором). Если неизменяемая переменная является нестатической локальной переменной, то она инициализируется во время выполнения (хотя, если значение является константой, компилятор может оптимизировать ее и инициализировать во время компиляции). Таким образом, вы можете создавать неизменяемые локальные переменные во время выполнения, в отличие от перечислений.
EDIT: Еще один случай, о котором я забыл: неизменяемые переменные-члены должны быть либо инициализированы непосредственно с помощью CTFE, либо инициализированы с помощью неизменяемого конструктора. Если неизменяемая переменная-член инициализируется непосредственно с помощью CTFE, то, очевидно, это делается во время компиляции, тогда как ее инициализация в неизменяемом конструкторе выполняется во время выполнения.
new
с CTFE. Это еще не так продвинуто.
- person Jonathan M Davis; 25.01.2011
new immutable(Temp)()
в порядке. Однако, если это переменная-член, это должно быть сделано в неизменяемом конструкторе. Вы не можете напрямую инициализировать неизменяемую переменную-член класса, потому что прямая инициализация переменной-члена должна выполняться со значением, которое генерируется CTFE, и в настоящее время вы не можете использовать new
с CTFE. Итак, объявите this(/*...*/) immutable {/*...*/}
и инициализируйте переменную-член внутри него.
- person Jonathan M Davis; 25.01.2011