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

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

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

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

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

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

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


person Prettygeek    schedule 31.01.2016    source источник
comment
Возможный дубликат инициализатора nonfailable enum со значением по умолчанию   -  person Kevin    schedule 01.02.2016


Ответы (2)


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

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

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

Это невозможно, я 3 возможных решения следующим образом:

1) Создание другого инициализатора

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

enum Language: String {

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

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

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

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

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
person Luca Angeletti    schedule 01.02.2016
comment
Фантастический ответ. Самость = ... была бесценна. Все виды скрытых самородков Swift на этом языке :) - person Marchy; 23.03.2017
comment
Вы можете заменить Language в инициализаторе подхода №1 на type(of: self).init для более общего подхода. - person shim; 30.08.2018

В дополнение к решению Луки по переопределению инициализации по умолчанию можно дополнительно сделать тип параметра 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, чтобы сохранить соответствие RawRepresentable.

person Nathan Hosselton    schedule 05.08.2017