Я хотел бы инициализировать enum связанным с ним значением.
Мое перечисление:
enum class DirectionSwiped(raw: Int){
LEFT(4),
RIGHT(8);
}
Я хотел бы инициализировать его как таковой:
val direction = DirectionSwiped(raw: 4)
Но я получаю такую ошибку:
Enum type cannot be instantiated
Почему это происходит? В Swift эта функция работает так:
enum Direction: Int {
case right = 2
}
let direction = Direction(rawValue: 2)
Как заставить его работать в Котлине?
Как говорится в ошибке, вы не можете создавать экземпляры перечислений в Kotlin. Возможный обходной путь - использовать карту и 2 вспомогательных метода для получения значений перечисления из необработанных значений и наоборот:
enum class DirectionSwiped {
LEFT,
RIGHT;
fun toRaw() = enumToRaw[this]
companion object {
val rawToEnum = mapOf(
4 to LEFT,
8 to RIGHT
)
val enumToRaw = rawToEnum.entries.associate{(k,v)-> v to k}
fun ofRaw(raw: Int): DirectionSwiped? = rawToEnum[raw]
}
}
Использование:
val direction = DirectionSwiped.ofRaw(4) // LEFT
val raw = DirectionSwiped.LEFT.toRaw() // 4
Совершенно небезопасно, DirectionSwiped.ofRaw(5)
возвращает null
, потенциально вызывая сбои во время выполнения
@OmarMainegra возвращает значение типа DirectionSwiped?
- обратите внимание на ?
. Так что да, конечно, он может вернуть null, что еще он вернет, если совпадения нет? Но благодаря типам Kotlin, допускающим значение NULL, это действительно спасает.
@Tagas И вы планируете сделать это для всех перечислений, которые вы определяете ?? также нет необходимости определять Map
, для этого достаточно DirectionSwiped.values().firstOrNull { it.raw == 5 }
@OmarMainegra Это зависит от количества перечисляемых значений. Если это всего лишь пара, то, конечно, ваше решение идеально подходит. Однако, если есть много значений и доступов, карта будет намного более производительной.
@Tagas, вам не хватает точки использования перечисления, они должны быть типами копродуктов, то же самое с запечатанным классом, иерархия закрытых типов для получения помощи от компилятора (например, инструкция when
), поэтому это опасно, не тогда используйте перечисления
Да, ты можешь
enum class DirectionSwiped(val raw: Int){
LEFT(4),
RIGHT(8);
}
val left = DirectionSwiped.LEFT
val right = DirectionSwiped.RIGHT
val leftRaw = DirectionSwiped.LEFT.raw
val rightRaw = DirectionSwiped.LEFT.raw
val fromRaw = DirectionSwiped.values().firstOrNull { it.raw == 5 }
Это был бы правильный способ доступа к экземплярам enum class
.
Что вы пытаетесь сделать, так это создать новый экземпляр вне сайта определения, что невозможно для классов enum
или sealed
, поэтому в ошибке говорится, что конструктор частный
Это, очевидно, работает, но вопрос заключался в получении значения enum по необработанному значению, а не в получении необработанного значения, если у вас уже есть значение enum ...
@Tagas Я тоже упоминаю об этом (например, fromRaw
), ваш ответ вводит в заблуждение, потому что он может и потерпит неудачу
Я не вижу вашей проблемы ... ваш DirectionSwiped.values().firstOrNull { it.raw == 5 }
возвращает тот же тип, что и моя функция ofRaw
: DirectionSwiped?
@Tagas Но я ясно выражаюсь, используя firstOrNull
, с первого взгляда вы видите, что он делает, в вашем случае нет
Будет предупреждение компилятора, я не знаю, как вы можете быть более явным, чем это ... В любом случае, давайте не будем добавлять больше бесполезных обсуждений, это никуда не денется.
@Tagas Вы правы, это бессмысленно, кстати, вы не видите предупреждения компилятора, когда читаете код в github, также общедоступные функции, такие как ваш toRaw
, должны явно указывать тип возвращаемого значения по той же причине (а вы этого не делаете это, поэтому сейчас сложно, когда ваша функция возвращает значение NULL)
Достаточно честно, позвольте мне это исправить :)
Спасибо за ответ, но мне кажется глупым, что на таком современном языке, как Kotlin, мы не можем делать это так, как быстро!