#swift #enums
#swift #перечисления
Вопрос:
Я пытаюсь сделать перечисление со связанным значением, соответствующим регистру, RawRepresentable. Меня устраивают некоторые значения по умолчанию для связанных значений при инициализации с помощью rawValue.
enum GenresAssociated: CaseIterable, RawRepresentable, Equatable {
case unknown(String)
case blues(String)
case classical(String)
// Implementing CaseIterable
typealias AllCases = [GenresAssociated]
// Enums can have no storage, but the class they are in CAN. Note 'static' in declaration
static var allCases: [GenresAssociated] = [.unknown(""), .blues(""), .classical("")]
typealias RawValue = Int
var rawValue: Int {
// MARK: This causes a crash for unknown reason
return GenresAssociated.allCases.firstIndex(where: { if case self = $0 { return true } else { return false } } ) ?? 0
}
init?(rawValue: Int) {
guard GenresAssociated.allCases.indices.contains(rawValue) else { return nil }
self = GenresAssociated.allCases[rawValue]
}
}
Есть ли какой-либо способ сделать это без переключения вручную по всем случаям, т. е. без такого кода:
typealias RawValue = Int
var rawValue: Int {
switch self {
case .unknown:
return 0
case .blues:
return 1
case .classical:
return 2
}
}
Примечательно то, что очень похожий код работает просто отлично, например
enum EnumWithValue {
case one(NSString!), two(NSString!), three(NSString!)
}
let arrayOfEnumsWithValues: [EnumWithValue] = [.one(nil), .two(nil), .three("Hey")]
if let index = arrayOfEnumsWithValues.firstIndex(where: { if case .two = $0 { return true }; return false }) {
print(".two found at index (index)") //prints ".two found at index 1"
}
Комментарии:
1. Я бы не стал использовать
RawRepresentable
для перечисления со связанными значениями, посколькуRawRepresentable
протокол указывает, что вы можете «переключаться между пользовательским типом и связанным типом rawValue без потери значения исходного RawRepresentable типа» ( developer.apple.com/documentation/swift/rawrepresentable ). Это означало бы, что ваши связанные значения также каким-то образом содержатся вrawValue
.2. Полностью согласен, @Palle. Структура данных является разновидностью kext (а также стресс-тестом для Enum). Да, я играю с перечислениями здесь, пытаясь освоить их.
Ответ №1:
Наконец-то я получил его для работы Mirror
!
var rawValue: Int {
let selfCaseName = Mirror(reflecting: self).children.first!.label!
return GenresAssociated.allCases.firstIndex(where: { (genre) in
let switchingCaseName = Mirror(reflecting: genre).children.first!.label!
return switchingCaseName == selfCaseName
})!
}
Не обращайте внимания на принудительное разворачивание, здесь это безопасно.
Комментарии:
1. Определенно рабочее решение, @J. Doe. Я также иногда использую Mirror в качестве последнего средства. Но я также пытаюсь выяснить, что не так с моим синтаксисом, т. Е. создаю ли я цикл памяти или сталкиваюсь с проблемой из-за лени или сбоев, или что-то в этом роде.
2. Не могли бы вы добавить еще несколько подробностей о том, как / почему это работает. Это потенциально может стать очень популярным (с большим количеством голосов) и полезным ответом. Спасибо
Ответ №2:
Этот параметр будет работать с перечислениями, содержащими как случаи rawValue, так и случаи с associatedValues:
var caseName: String {
let result = String(describing: self)
let assocValName = Mirror(reflecting: self).children.first?.label ?? "failed"
return !result.contains("(") ? result : assocValName
}