web-dev-qa-db-fra.com

Remplacer Enum init? (RawValue: String) pour ne pas être facultatif

Je veux avoir init de rawValue pour mon énumération dans Swift pour retourner la valeur par défaut si rawValue init retournera nil. En ce moment, j'ai quelque chose comme ceci:

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

Je n'aime pas ça car c'est un tout nouvel initialiseur. J'ai essayé de faire quelque chose comme ça:

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

Mais j'ai une exception d'exécution avec un mauvais accès. Puis-je en quelque sorte le faire fonctionner ou je dois juste utiliser ce nouveau et je ne peux pas remplacer celui d'origine pour ne pas être facultatif?

Je voudrais savoir s'il est possible de remplacer l'initialisation d'origine de rawValue et non une solution de contournement par une toute nouvelle qui utilise une option disponible.

44
Prettygeek

L'initialiseur par défaut est failable. Cela signifie que si le paramètre reçu ne correspond pas à un cas d'énumération valide, il renvoie nil.

Maintenant, vous voulez faire 2 choses incompatibles:

  1. Vous voulez redéfinir l'initialiseur par défaut le rendant non disponible. En fait, vous voulez une valeur d'énumération par défaut créée lorsque le paramètre reçu n'est pas valide.
  2. Dans votre initialiseur redéfini, vous souhaitez appeler un initialiseur disponible (qui n'existe plus) en utilisant le même nom que le nouveau.

Ce n'est pas possible, je les 3 solutions possibles comme suit:

1) Créer un init différent

Vous définissez un nouvel initialiseur non disponible avec une valeur par défaut, un nom de paramètre différent et à l'intérieur, vous appelez l'initialiseur disponible par défaut.

enum Language: String {

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

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

2) Redéfinir l'initialisation par défaut

Vous redéfinissez l'initialiseur par défaut, vous le rendez non disponible et vous y écrivez la logique complète.

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) Création d'une fonction statique

enum Language: String {

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

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

Vous pouvez maintenant construire une écriture de valeur Language:

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

En ajoutant à la solution de Luca pour redéfinir l'initialisation par défaut, il est également possible de rendre facultatif le type de paramètre rawValue, ce qui réduit le code sur le site d'appel lorsque la source de données n'est pas fiable.

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
        }
    }
}

Lorsque j'ai d'abord essayé cela, cela a généré plusieurs erreurs. La clé était de redéfinir les typealias RawValue pour maintenir la conformité à RawRepresentable.

5
Nathan Hosselton