Vérifier le type d'énumération Swift

Aperçu

Ceci est un article pour les débutants. Même si vous n'êtes pas débutant, vous découvrirez peut-être quelque chose. J'écrirai sur l'énumération de la grammaire Swift.

Fonctionnement confirmé avec Swift 5.3

Premier problème

La valeur brute et la valeur associée peuvent-elles être utilisées en même temps dans l'énumération de Swift?

Si vous savez cela, vous n'aurez peut-être pas besoin de lire cet article en particulier.

enum C'est ce qu'on appelle un type d'énumération. Défini avec enum et case.

enum CompassPoint {
    case north
    case south
    case east
    case west
}

Stocker dans la variable

Les variables sont ** singulières **. Si vous connaissez le type d'énumération de la variable, vous pouvez omettre le type comme .east.

var directionToHead = CompassPoint.north
directionToHead = .south

var directionToHeadLast: CompassPoint = .east

Switch Dans l'instruction Switch, une erreur de compilation se produit si tous les cas d'énumération ne sont pas couverts. Vous pouvez également utiliser default.

switch directionToHead {
case .north, .east, .south, .west: print("direction")
}

switch directionToHead {
case .north, .east, .south: print("direction")
default: print("other")
}

Tournez l'itération

En ajoutant CaseIterable, vous pouvez transformer l'élément d'énumération avec une instruction for.

C'est comme ça


enum CompassPoint: CaseIterable {
    case north
    case south
    case east
    case west
}


CompassPoint.allCases.forEach{print($0)}

Cela produira ce qui suit:

north
south
east
west

Associated Values

Il est possible de donner une valeur à chaque élément d'énumération.


enum Appliance {
    case light(isOn: Bool)
    case airCon(degree: Int, isOn: Bool)
}

var appliance: Appliance
appliance = .light(isOn: true)
appliance = .airCon(degree: 28, isOn: true)

Lorsque vous l'utilisez dans une instruction Switch, vous pouvez récupérer la valeur associée avec let ou var.

switch appliance {
case .light(let isOn):
    print(isOn)
case .airCon(let degree, let isOn):
    print(isOn, degree)
}

Notez que le Case Iterable sorti précédemment ne peut pas être utilisé pour les énumérations avec ** Valeurs associées **!

Un peu de technique

Lorsque la valeur associée est all let ou all var, elle est multipliée comme suit.


switch appliance {
case let .light(isOn):
    print(isOn)
case let .airCon(degree, isOn):
    print(isOn, degree)
}

Vous n'êtes pas obligé d'écrire plusieurs let en mettant let devant!

Raw Values

Contrairement aux valeurs associées, vous pouvez mettre des ** valeurs qui sont ** fixées au moment de l'écriture dans chaque cas d'énumération.

enum Step: Int {
    case one = 1
    case two = 2
    case three = 3
}

print(Step.three.rawValue)

Cela affichera «3».

enum Step: Int {
    case one, two, three
}

print(Step.one.rawValue)

Que pensez-vous que cela montrera?

Réellement

0

Est affiché.

Ce n'est que lorsqu'il s'agit d'une valeur brute de Int ou de chaîne, la valeur est entrée sans autorisation. Dans le cas de Int, «0» entre dans le premier cas et est incrémenté un par un. Dans le cas de String, le nom du cas lui-même est entré.

De plus amples recherches

Faisons plus sur la valeur brute. Cela posera des problèmes, alors devinons la chaîne de caractères de sortie.

Q1

enum Step: Int,CaseIterable {
    case one, two, three=99
}

Step.allCases.forEach{print($0.rawValue)}

<détails>

Réponse Q1 </ summary>

0
1
99

Q2


enum Step: Int,CaseIterable {
    case one, two=99, three
}

Step.allCases.forEach{print($0.rawValue)}

<détails>

Réponse Q2 </ summary>

0
99
100

Q3


enum Step: Int,CaseIterable {
    case one=12, two=11, three
}

Step.allCases.forEach{print($0.rawValue)}

<détails>

Réponse Q3 </ summary>

Il y a une erreur de compilation. Pour trois, 12 est entré, ce qui est un incrément de 11 pour deux, mais je me fâche parce que cela est couvert par un.

Q4


enum Step: Int8,CaseIterable {
    case one, two=127, three
}

Step.allCases.forEach{print($0.rawValue)}

<détails>

Réponse Q4 </ summary>

C'est aussi une erreur de compilation Int8 a un maximum de 127, donc je me fâche lorsque les trois valeurs dépassent int8.

error: MyPlayground.playground:12:24: error: integer literal '128' overflows when stored into 'Int8'
    case one, two=127, three

Initialiser avec la valeur brute

Cela peut aller de rawValue à enum. Notez que si vous spécifiez une valeur qui n'est pas dans enum, elle sera ** nil **!


enum Step: Int, CaseIterable {
    case one=1, two, three
}

Step(rawValue: 2) // two
Step(rawValue: 4) // nil

En d'autres termes, la valeur de retour sera facultative lors de l'initialisation avec rawValue. Utiliser la liaison facultative lors de l'initialisation avec rawValue

guard let step = Step(rawValue: 4) else {
    fatalError("undefined!!")
}

La valeur brute et la valeur associée peuvent-elles être utilisées en même temps dans l'énumération de Swift?

C'est le premier problème.

La réponse est «peut»

Si vous l'avez fait normalement, ce code


enum CompassPoint: String {
    case north(Int)
    case south(Int)
    case east(Int)
    case west(Int)
}

J'obtiens une erreur de compilation.

'CompassPoint' declares raw type 'String', but does not conform to RawRepresentable and conformance could not be synthesized

Cependant, en réalité, il peut être géré.

La manière d'écrire la valeur brute d'énumération expliquée cette fois est appelée «notation abrégée». Il est écrit comme suit.


enum Test: String {
    case pass = "Yay!"
}

La condition pour réaliser RawValue est le respect du protocole «RawRepresentable», qui se trouve également dans l'erreur de compilation ci-dessus. Si le cas a au moins une valeur associée, la «notation abrégée» ne sera plus automatiquement conforme à «RawRepresentable». Ainsi, vous pouvez utiliser la valeur brute et la valeur associée en même temps en procédant comme suit.

enum TestResult {
    case pass(Int)
    case fail(Int)
}

extension TestResult: RawRepresentable {
    typealias RawValue = String
    
    init?(rawValue: RawValue) {
        switch rawValue {
        case "Yay!": self = .pass(1)
        case "Pardon ...": self = .fail(0)
        default:
            return nil
        }
    }
    
    var rawValue: RawValue {
        switch self {
        case .pass: return "Yay!"
        case .fail: return "Pardon ..."
            
        }
    }
}

TestResult.pass(1).rawValue //Yay!
TestResult.fail(0).rawValue //Pardon ...

Notez que vous devez saisir la valeur associée lors de l'initialisation.

Après tout, la manière d'écrire RawValue de notation abrégée 'n'est qu'une courte expression, et il semble que le compilateur en fasse RawRepresentable` comme ci-dessus. (Référence: The RawRepresentable Protocol in Swift - Ole Begemann)

Énumération récursive

Si vous souhaitez utiliser enum de manière récursive pour une valeur associée, vous devez ajouter le mot clé indirect à ce cas.


enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression) //Récursif car l'argument ici se contient
}

Indirect peut également être amené au début de l'énumération.

indirect enum ArithmeticExpression: CustomStringConvertible {
    case number(Int)
    case addition(ArithmeticExpression, ArithmeticExpression)
}

Sans indirect?

Erreur de compilation

error: MyPlayground.playground:2:6: error: recursive enum 'ArithmeticExpression' is not marked 'indirect'
enum ArithmeticExpression: CustomStringConvertible {
     ^
indirect 

J'ai essayé d'afficher une chaîne de caractères pendant un moment

let expression = ArithmeticExpression.addition(.number(10), .addition(.number(1), .number(2)))

print(expression.description)

Je souhaite afficher l'expression sous forme de chaîne de caractères dans l'impression ci-dessus. J'ai essayé d'afficher la chaîne de caractères de l'expression de manière récursive à l'aide de CustomStringConvertible.

enum ArithmeticExpression: CustomStringConvertible {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    
    var description: String {
        get {
            switch self {
            case .number(let num):
                return String(num)
            case .addition(let expr1, let expr2):
                return "\(expr1.description) + \(expr2.description)"
            }
        }
    }
}

Est-ce que c'est comme ça?

10 + 1 + 2

Il a été affiché en toute sécurité!

Sommaire

  • L'énumération Swift doit mémoriser les valeurs associées et les valeurs brutes
  • Les valeurs associées permettent à la casse d'avoir des valeurs
  • RawValue peut être défini sur la valeur correspondant au cas.
  • ** Les valeurs associées et la valeur brute peuvent être utilisées en même temps **
  • N'oubliez pas ʻindirect` pour une énumération récursive!

référence