Подтвердить что ты не робот

Переопределение Enum init? (RawValue: String), чтобы не было необязательным

Я хочу, чтобы init из rawValue для моего перечисления в Swift возвращал значение по умолчанию, если rawValue init вернет нуль. Прямо сейчас у меня есть что-то вроде этого:

public init(fromRawValue: String){
        self = Language(rawValue: fromRawValue) ?? .English
}

Мне это не нравится, потому что это совершенно новый инициализатор. Я попытался сделать что-то вроде этого:

public init(rawValue: String){
        self = Language(rawValue: fromRawValue) ?? .English
}

Но у меня есть исключение во время выполнения с плохим доступом. Могу ли я каким-то образом заставить его работать, или мне просто нужно использовать это новое, и я не могу переопределить оригинал, чтобы он не был необязательным?

Я хотел бы знать, можно ли переопределить исходный init из rawValue, а не обходной, с полностью новым, который использует отказоустойчивый.

4b9b3361

Ответ 1

Инициализатор по умолчанию failable. Это означает, что если полученный параметр не соответствует действительному регистру enum, он возвращает nil.

Теперь вы хотите сделать 2 несовместимых вещи:

  • Вы хотите переопределить инициализатор по умолчанию, что делает его невозможным. Infact вы хотите, чтобы значение enum по умолчанию было создано, когда полученный параметр недействителен.
  • Внутри переопределенного инициализатора вы хотите вызвать инициализатор с ошибкой (который больше не существует) с использованием того же имени нового.

Это невозможно, я 3 возможных решения:

1) Создание другого init

Вы определяете новый инициализатор с неисполнением со значением по умолчанию, другое имя параметра и внутри него вы вызываете инициализатор по умолчанию.

enum Language: String {

    case english = "English", italian = "Italian", french = "French"

    init(fromRawValue: String){
        self = Language(rawValue: fromRawValue) ?? .english
    }
}

2) Переопределение init по умолчанию

Вы переопределяете инициализатор по умолчанию, вы делаете его невоспроизводимым, и вы пишете полную логику внутри него.

enum Language: String {

    case english = "English", italian = "Italian", french = "French"

    init(rawValue: String) {
        switch rawValue {
        case "Italian": self = .italian
        case "French": self = .french
        default: self = .english
        }
    }
}

3) Создание статической функции

enum Language: String {

    case english = "English", italian = "Italian", french = "French"

    static func build(rawValue:String) -> Language {
        return Language(rawValue: rawValue) ?? .english
    }
}

Теперь вы можете построить запись значения Language:

let italian = Language.build(rawValue: "Italian") // Italian
let defaultValue = Language.build(rawValue: "Wrong input") // English

Ответ 2

Добавление в решение Luca для переопределения инициализации по умолчанию можно дополнительно сделать необязательным параметр параметра rawValue, который сокращает некоторый код на сайте вызова, когда источник данных не является надежным.

enum PrecipitationType: String {
    case rain, snow, sleet, none

    typealias RawValue = String

    init(rawValue: String?) {
        guard let rawValue = rawValue else { self = .none; return }

        switch rawValue {
            case PrecipitationType.rain.rawValue: self = .rain
            case PrecipitationType.snow.rawValue: self = .snow
            case PrecipitationType.sleet.rawValue: self = .sleet
            default: self = .none
        }
    }
}

Когда я изначально попробовал это, он породил несколько ошибок. Ключ должен был переопределить тип rawValue typealias, чтобы поддерживать соответствие с RawRepresentable.