enumerations Define a common type for a set of related values so that you can use them in a type-safe manner in your code.
If you're familiar with C, you'll know that in C, enumerations assign names that are associated with a set of integer values. The enumerations in Swift are more flexible and do not have to provide a value for each enumeration member. If you supply an enumeration member with a value (called the "original" value), the type of the value can be a string, a character, or an integer value or a floating-point number.
In addition, enumeration members can specify that any type of association value is stored in an enumeration member, like a Union (unions) and variant (variants) in other languages. Each enumeration member can have an appropriate type of associated value.
In Swift, the enumeration type is a-first-class type. They employ a number of features that have traditionally been supported only by Class (class), such as computed attributes (computed properties), which provide additional information on enumeration values, instance methods (instance methods), which provide functionality associated with enumeration values. Enumerations can also define constructors (initializers) to provide an initial value, to extend their functionality on the basis of the original implementation, and to comply with the Protocol (protocols) to provide standard functionality.
Enumeration syntax
Useenumkeywords to create enumerations and place their entire definition within a pair of curly braces:
enum SomeEnumeration {
// enum definitions are placed here
}
The following is an example of using enumerations to represent four directions in a compass:
enum CompassPoint {
case North
case South
case East
case West
}
The values defined in the enumeration (for exampleNorth,South,EastandWest) are the member values (or members ) of this enumeration. You usecasethe keyword to define a new enumeration member value.
Attention
Unlike C and Objective-c, Swift's enumeration members are not assigned a default integer value when they are created. In the aboveCompassPointexample,,North,SouthEastandWestwill not be implicitly assigned to,01,2and3. Instead, these enumeration members are self-contained values, and the types of these values are well-definedCompassPointtypes.
Multiple member values can appear on the same line, separated by commas:
enum Planet { case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
Each enumeration defines a completely new type. Like other types in Swift, their names (such asCompassPointandPlanet) should start with a capital letter. A single-digit name instead of a plural name for an enumeration type to make it easier to read:
var directionToHead = CompassPoint.West
directionToHeadType can beCompassPointinferred when it is initialized by a value. OncedirectionToHeaddeclared as aCompassPointtype, you can set it to another value using a shorter point syntaxCompassPoint:
directionToHead = .East
WhendirectionToHeadthe type is known, the enumeration type name can be omitted again for its assignment. This notation makes your code more readable when you use an enumeration value that has an explicit type.
To match an enumeration value with a Switch statement
You can useswitchstatements to match a single enumeration value:
directionToHead = .South
switch directionToHead {
case .North:
print("Lots of planets have a north")
case .South:
print("Watch out for penguins")
case .East:
print("Where the sun rises")
case .West:
print("Where the skies are blue")
}
// 输出 "Watch out for penguins”
You can understand this code this way:
"directionToHeadthe value of the judgment. When it equals.North, print“Lots of planets have a north”. When it equals.South, print“Watch out for penguins”. ”
...... And so on
As described in control flow, theswitchstatement must be exhaustive in all cases when judging the value of an enumerated type. If this is omitted.West, the code above will not compile because it does not take into accountCompassPointall the members. Forced exhaustive ensures that enumeration members are not accidentally omitted.
When you do not need to match each enumeration member, you can provide adefaultbranch that covers all the enumerated members that are not explicitly handled:
let somePlanet = Planet.Earth
switch somePlanet {
case .Earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
// print "Mostly harmless”
Association value (associated values)
The example in the previous section shows how to define and categorize the members of an enumeration. You canPlanet.Earthset a constant or variable and look at the value after the assignment. However, it is sometimes useful to be able to store other types of association values together with member values. This allows you to store additional custom information along with the member values, and you can modify the associated value each time you use the enumeration member in your code.
You can define Swift enumerations to store any type of association value, and the associated value types for each enumeration member can vary, if required. This attribute of the enumeration is similar to the recognizable union (discriminated unions) in other languages, the label union (tagged unions), or the variant (variants).
For example, suppose an inventory tracking system needs to use two different types of barcodes to track goods. Some products have09a one-dimensional barcode in the UPC-A format labeled with the numbers used. Each barcode has a number representing the "digital system" followed by five digits representing the "Vendor Code", followed by five digits representing the "Product Code". The last number is the "check" bit to verify that the code is scanned correctly:
Other products are labeled QR code format, it can use any ISO 8859-1 characters, and can encode a maximum of 2,953 characters of the string:
This facilitates the inventory tracking system to store upc-a codes with tuples of four integer values, as well as to store QR codes with arbitrary-length strings.
In Swift, an enumeration that represents two commodity barcodes is defined using the following method:
enum Barcode {
case UPCA(Int, Int, Int, Int)
case QRCode(String)
}
The above code can understand this:
"Defines anBarcodeenumeration type named with one member value that has a(Int,Int,Int,Int)type associated valueUPCAand another member value that has aStringtype associated valueQRCode. ”
This definition does not provide anyIntorStringtype of association values, it simply defines theBarcodetype ofBarcode.UPCABarcode.QRCodeassociated values that can be stored when constants and variables are equal or.
You can then create a new barcode using any one of the barcode types, for example:
var productBarcode = Barcode.UPCA(8, 85909, 51226, 3)
The above example creates aproductBarcodevariable named, and assigns it a value of theBarcode.UPCAassociated tuple value(8, 85909, 51226, 3).
The same product can be assigned a different type of barcode, for example:
productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
At this point, the originalBarcode.UPCAand its integer associated value is replaced by the newBarcode.QRCodeand its string associated value.BarcodeConstants and variables of type can store one.UPCAor the other.QRCode(along with their associated values), but only one of these two values is stored at the same time.
As before, you can use a switch statement to check the different barcode types. This time, however, the correlation value can be extracted as part of the switch statement. You canswitchextract each associated value in the case branch code as a constant (letprefixed) or as a variable (varprefixed) to use:
switch productBarcode {
case .UPCA(let numberSystem, let manufacturer, let product, let check):
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case .QRCode(let productCode):
print("QR code: \(productCode).")
}
//print"QR code: ABCDEFGHIJKLMNOP."
If all the associated values of an enumeration member are extracted as constants, or all are extracted as variables, for brevity, you can simply label one or more of the member namesletvar:
switch productBarcode {
case let .UPCA(numberSystem, manufacturer, product, check):
print("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
case let .QRCode(productCode):
print("QR code: \(productCode).")
}
// print "QR code: ABCDEFGHIJKLMNOP."
Original value (Raw values)
In the bar code example of the associated Values section, demonstrates how to declare an enumeration member that stores different types of associated values. As an alternative to associative values, enumeration members can be pre-populated by default values, known as raw values, and the types of these original values must be the same.
This is an enumeration that uses ASCII code as the original value:
enum ASCIIControlCharacter: Character {
case Tab = "\t"
case LineFeed = "\n"
case CarriageReturn = "\r"
}
ASCIIControlCharacterthe original value type of the enumeration type is defined asCharacter, and some of the more common ASCII control characters are set.Charactersee the string and character sections for a description.
The original value can be a string, a character, or an arbitrary integer value or a floating-point value. Each original value must be unique within the enumeration declaration.
Attention
The original value and the associated value are different. The original value is a value that is prepopulated when the enumeration is defined, like the above three ASCII codes. For a particular enumeration member, its original value is always the same. An association value is a value that is set when a constant or variable is created based on an enumeration member, and the associated value of an enumeration member can vary.
Implicit assignment of the original value (implicitly Assigned raw values)
You do not need to explicitly set the original value for each enumeration member when using an enumeration of the original value as an integer or string type, and Swift will automatically assign you a value.
For example, when an integer is used as the original value, the value of the implicitly assigned value is incremented sequentially1. If the first enumeration member does not have the original value set, its original value will be0.
The following enumeration is a refinement of the previousPlanetenumeration, using the primitive values of integers to represent the order of each planet in the solar system:
enum Planet: Int {
case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
In the example above,Plant.Mercurythe explicit original value is1,Planet.Venusthe implicit original value is2, and so on.
When a string is used as the original value of an enumeration type, the implicit original value of each enumeration member is the name of the enumeration member.
The following example is a refinement of anCompassPointenumeration that uses the original value of a string type to represent the names of each direction:
enum Planet: Int { case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
In the example above, there isCompassPoint.Southan implicit primitive valueSouth, and so on.
TherawValueoriginal value of the enumeration member can be accessed by using the properties of the enumeration member:
let earthsOrder = Planet.Earth.rawValue
// earthsOrder value is 3
let sunsetDirection = CompassPoint.West.rawValue
// sunsetDirection value is "West"
Initializes an enumeration instance with raw values (Initializing from a raw value)
If the original value is used when defining an enumeration type, an initialization method is automatically obtained, which takes arawValueparameter called, the parameter type is the original value type, and the return value is an enumeration member ornil. You can use this initialization method to create a new enumeration instance.
This example7creates an enumeration member with the original valueUranus:
let possiblePlanet = Planet (rawValue: 7)
// possiblePlanet type is Planet? Value is Planet.Uranus
However, not allIntvalues can be found for a matching planet. Therefore, the primitive value builder always returns an optional enumeration member. In the example above,possiblePlanetit is thePlanet?type, or "optionalPlanet".
Attention
The primitive value constructor is a failed constructor, because not every original value has an enumeration member corresponding to it. For more information, see failed constructors
If you are trying to find a location for a9planet, the optional values returned by the original value constructorPlanetwill benil:
let positionToFind = 9
if let somePlanet = Planet (rawValue: positionToFind) {
switch somePlanet {
case .Earth:
print ("Mostly harmless")
default:
print ("Not a safe place for humans")
}
} else {
print ("There is n‘t a planet at position \ (positionToFind)")
}
// Output "There is n‘t a planet at position 9
This example uses an optional binding (optional binding) to attempt to access a planet by its original value9.if let somePlanet = Planet(rawValue: 9)statement creates an optionalPlanet, if an optionalPlanetvalue exists, it is assigned tosomePlanet. In this example, the location9of the planet cannot be retrieved, so theelsebranch is executed.
Recursive enumeration (Recursive enumerations)
When a variety of possible situations can be exhaustive, it is well suited to use enumerations for data modeling, such as an enumeration to represent operators for simple integer operations. These operators allow you to combine simple arithmetic expressions, such as integers,5into more complex expressions, for example5 + 4.
An important feature of arithmetic expressions is that expressions can be nested. For example, an expression(5 + 4) * 2, the right side of multiplication sign is a number, and the left is another expression. Because the data is nested, the enumeration type used to store the data also needs to support this nesting-meaning that the enumeration type needs to support recursion.
A Recursive enumeration (recursive enumeration) is an enumeration type that has one or more enumeration members that use an instance of the enumeration type as the associated value. When recursive enumeration is used, the compiler inserts an indirection layer. You can add a member before the enumerationindirectto indicate that the member is recursive.
For example, in the following example, an enumeration type stores a simple arithmetic expression:
enum ArithmeticExpression {
case Number(Int)
indirect case Addition(ArithmeticExpression, ArithmeticExpression)
indirect case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
You can also add a keyword at the beginning of an enumeration typeindirectto indicate that all its members are recursive:
indirect enum ArithmeticExpression {
case Number(Int)
case Addition(ArithmeticExpression, ArithmeticExpression)
case Multiplication(ArithmeticExpression, ArithmeticExpression)
}
The enumerated types defined above can store three arithmetic expressions: a pure number, a total of two expressions, and a two-expression multiplication. An enumeration memberAdditionandMultiplicationits associated values are also arithmetic expressions--these associated values make it possible to nest an expression.
To manipulate data structures with recursive properties, using recursive functions is a straightforward approach. For example, here is a function that evaluates an arithmetic expression:
func evaluate (expression: ArithmeticExpression)-> Int {
switch expression {
case .Number (let value):
return value
case .Addition (let left, let right):
return evaluate (left) + evaluate (right)
case .Multiplication (let left, let right):
return evaluate (left) * evaluate (right)
}
}
// calculate (5 + 4) * 2
let five = ArithmeticExpression.Number (5)
let four = ArithmeticExpression.Number (4)
let sum = ArithmeticExpression.Addition (five, four)
let product = ArithmeticExpression.Multiplication (sum, ArithmeticExpression.Number (2))
print (evaluate (product))
// print "18"
If the function encounters a pure number, it returns the value of the number directly. If an addition or multiplication is encountered, the values of the left and right expressions are computed separately and then added or multiplied.
Attack on Swift-------------enumeration