Фон
У меня есть перечисление, которое, упрощенно, выглядит так:
enum Container<T> {
case a(T)
case b(T)
case c
}
Я хочу иметь возможность создать его с несколькими различными типами для обобщенного c и используйте для этого typealias
:
typealias IntContainer = Container<Int>
typealias FloatContainer = Container<Float>
Задача
Пока все в порядке. Однако я также хочу создать рекурсивный экземпляр этого:
typealias CyclicContainer = Container<CyclicContainer>
Swift сообщает об этом с ошибкой компиляции:
Псевдоним типа 'CyclicContainer' ссылается на себя
… Эта ошибка все еще появляется, когда я изменяю объявление Container
на:
indirect enum Container<T>
Это немного раздражает, потому что это будет полезным и компилирующим Swift :
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
Обходной путь 1
Для этого есть обходной путь. Я могу объявить, например:
indirect enum CyclicContainer {
case container(Container<CyclicContainer>)
}
… Однако, это становится неудобным для кратких описаний экземпляра CyclicContainer
:
let cyclicContainer: CyclicContainer = .container(.a(.container(.b(.container(.c)))))
Вместо просто:
let cyclicContainer: CyclicContainer = .a(.b(.c))
Обходной путь 2
Я также мог бы просто создать отдельное перечисление для рекурсивного случая, как показано ранее:
indirect enum CyclicContainer {
case a(CyclicContainer)
case b(CyclicContainer)
case c
}
Однако мне потребуется: создать функции для преобразования от CyclicContainer
до Container
; повторно реализовать различные функции-члены, которые существуют в Container<T>
; и сохраняйте эти два типа в будущем c, если я добавлю новый случай или изменим имя случая.
Это не очень сложно, и к этому я склоняюсь. Но, кажется, стыдно делать это, когда Swift может справиться с indirect enum
совершенно счастливо, но не тогда, когда это вызвано созданием аргумента generi c в перечислении.
Вопрос
Есть ли лучший способ?