• 1000 *,
medium = 1
и так далее. Итак, размер
Size
составляет 1 байт, что можно проверить с помощью
MemoryLayout<Size>.size
. Я также отметил, что если перечисление имеет более 255 случаев, очевидно, что размер тега увеличивается до 2 байтов.
enum Size {
case small
case medium
case large
}
Второй случай, если перечисление имеет связанные значения, оно ведет себя как объединение. В этом случае размер перечисления - это размер тега плюс размер наибольшего связанного значения. В следующем примере размер составляет 1 байт + 16 байтов (String), то есть 17 байтов, что также можно проверить с помощью MemoryLayout
.
enum Value {
case int(Int)
case double(Double)
case string(String)
case bool(Bool)
}
Последний случай, поскольку Swift является безопасным языком, ссылки всегда действителен с использованием стандартного небезопасного кода Swift, т.е. всегда указывает на значение в памяти. Это позволяет компилятору оптимизировать такое перечисление, когда T
является ссылочным типом:
enum Opt<T> {
case none
case some(T)
}
Здесь экземпляр типа T
не может быть nil
(NULL), поэтому компилятор использует это специальное значение для случай none
, следовательно, Opt
имеет размер 8 байтов вместо 9 байтов, когда T
является ссылочным типом. Эта оптимизация поднята в this SO вопрос о Rust, который, как я считаю, имеет такое же поведение, как Swift в отношении перечислений.
Например, с этим простым ссылочным типом MemoryLayout
возвращает размер 8 байтов:
class Person {
var name: String
init(name: String) {
self.name = name
}
}
let p = Opt.some(Person(name: "Bob")) // 8 bytes
Вопрос
То, что я не могу понять, так это размер этого перечисления (все еще когда T является ссылочным типом):
enum Opt<T> {
case none
case secondNone
case some(T)
}
Почему это тоже 8 байтов, согласно MemoryLayout
?
В моем понимании это должно быть 9 байтов. Оптимизация NULL возможна только потому, что none
может быть представлено NULL, но в моем примере нет «второго» значения NULL для secondNone
, поэтому здесь должен потребоваться тег для различения случаев.
Компилятор автоматически превращает это перечисление в ссылочный тип (аналогично перечислению indirect
) из-за этого? Это объяснило бы размер 8 байтов. Как я могу проверить эту последнюю гипотезу?