Enum Original value
1.1 Basic Usage
Swift uses the enum keyword to declare an enumeration:
enum SSLEnum {
case test_one
case test_two
case test_three
}
Copy the code
We know that C and OC accept integers by default, which means that in the following example: A, B, and C default to 0, 1, and 2 respectively
typedef NS_ENUM(NSInteger, SSLEnum) {
A,
B,
C,
};
Copy the code
Enumerations in Swift are more flexible and do not need to provide a value for every member of the enumeration. If you supply a value for an enumeration member (called a primitive value), the value can be a string, a character, an arbitrary integer value, or a floating-point type.
enum Color: String { case red = "Red" case amber = "Amber" case green = "Green" } enum SSLEnum: Double {case a = 10.0 case b = 20.0 case c = 30.0 case d = 40.0}Copy the code
Implicit RawValue allocation is built on Swift’s type inference mechanism.
enum DayOfWeek: String { case mon, tue, wed, thu, fri = "Hello World", sat, Sun} print(dayofweek.rawValue) print(dayofweek.fri.rawValue) print(dayofweek.rawValue) Print (dayofweek.rawValue) Mon Hello World satCopy the code
We can see that the enumeration values of mon and STA are the same as the original values. Let’s see how this is done.
1.2 Sil analysis value process
Add the following code:
enum DayOfWeek: String {
case mon, tue, wed, thu, fri = "Hello World", sat, sun
}
var x = DayOfWeek.mon.rawValue
Copy the code
Swiftc-ema-sil main.swift >./main.sil && open main.sil generates sil files:
Enum DayOfWeek: String {case mon, tue, wed, thu, FRI, SAT, sun? Typealias rawValue = String var rawValue: String {get} // get function}Copy the code
To get a rawValue, call the get method in the sil file.
If it is mon, then bb1 is called, and the string constant is “mon”. Where is the string constant?
The storage location is as follows:
1.3 Enumeration values and raw values
Enumeration values and primitive values cannot be assigned to each other:
Second, the correlation value
2.1 Basic Usage
Sometimes we want to express something more complex with enumerated values, such as shapes:
Enum Shape {case circle(radios: Double) // Rectangle (width: Double, height: // radios: 1 var circle = shape. circle(radios: 10)Copy the code
2.2 Pattern Matching
Switch pattern matching
enum Weak: String {
case MONDAY
case TUEDAY
case WEDDAY
case THUDAY
case FRIDAY
case SATDAY
case SUNDAY
}
let currentWeak: Weak = Weak.MONDAY
switch currentWeak {
case .MONDAY: print(Weak.MONDAY.rawValue)
case .TUEDAY: print(Weak.MONDAY.rawValue)
case .WEDDAY: print(Weak.WEDDAY.rawValue)
case .THUDAY: print(Weak.THUDAY.rawValue)
case .FRIDAY: print(Weak.FRIDAY.rawValue)
case .SATDAY: print(Weak.SATDAY.rawValue)
case .SUNDAY: print(Weak.SUNDAY.rawValue)
}
Copy the code
If you do not want to match all cases, use the default keyword:
enum Weak: String {
case MONDAY
case TUEDAY
case WEDDAY
case THUDAY
case FRIDAY
case SATDAY
case SUNDAY
}
let currentWeak: Weak = Weak.MONDAY
switch currentWeak {
case .SATDAY, .SUNDAY: print("Happy Day")
default : print("SAD Day")
}
Copy the code
If we want to match the correlation value:
enum Shape{ case circle(radious: Double) case rectangle(width: Int, height: Int) } let shape = Shape.circle(radious: Rectangle {case let. circle(radious): print(" circle radious:\(radious)") case let. rectangle(width, height): print("rectangle width:\(width),height\(height)") }Copy the code
You can also write:
enum Shape{ case circle(radious: Double) case rectangle(width: Int, height: Int) } var shape = Shape.circle(radious: 10.0) Switch Shape {case. Circle (let radious): print("Circle radious:\(radious)") case .rectangle(let width, let height): print("rectangle width:\(width),height\(height)") }Copy the code
Enumerate size
3.1 No – content enums
So let’s talk about the size of the memory that enumerations take up, and there are several different kinds of cases. The first one is the no-payload enums, which are enumerations that have No associated values.
enum Week {
case MONDAY
case TUEDAY
case WEDDAY
case THUDAY
case FRIDAY
case SATDAY
case SUNDAY
}
Copy the code
As you can see, enumerations of this type are similar to enumerations in C. The default type is Int. And how much memory does it take up? Here we can measure the current enumeration directly using MemoryLayout
- You can see that both the size and stribe that we tested here are 1
- Enumeration layouts in Swift have always tried to store enUms with minimal space, with 1 byte representing 256 cases
- That is, a default enumeration type with no associated value and case less than 256. The current enumeration type is all 1 byte in size
UInt8
According to the above print, we can see intuitively that the contents of the three variables a, b and c are 00,01,02 respectively, which is consistent with the layout understanding we said above.
3.2 Single – content enums
Let’s look at the memory layout of single-payload enums, which literally means an enum with only one payload, as in the following example
enum SSLEnum { case test_one(Bool) case test_two case test_three case test_four } enum SSLEnum2 { case test_one(Int) case test_two case test_three case test_four } print(MemoryLayout<SSLEnum>.size) print(MemoryLayout<SSLEnum2>.size) The output is as follows: 1 9Copy the code
- Why is there a single load, but the current occupancy is not the same size!
- Pay attention to,
Swift
Enum inSingle-payload enums
The extra space in the load type is used to record case values that are not loaded. - for
Bool
Type versus load,Bool
The type is 1 byte, but it only takes 1 bit to store, forUInt8
For enumerations of types, there is still 7 bits of space to represent 128 cases, so 1 byte is fine. - for
Int
Type of load, in fact, the system is no way to calculate the current load to use the number of bits, which means the currentInt
Type loads have no extra free space, so we need to allocate extra memory to store our case values, which are 8 + 1 = 9 bytes.
3.3 Mutil – content enums
The third case is mutil-payload enums, where there are multiple loads.
Look at the following example:
enum SSLEnum { case test_one(Bool) case test_two(Bool) case test_three case test_four } enum SSLEnum2 { case test_one(Int) case test_two(Int) case test_three(Int) case test_four(Int) } enum SSLEnum3 { case test_one(Bool) case test_two(Int) case test_three case test_four } enum SSLEnum4 { case test_one(Int, Int, Int) case test_two case test_three case test_four } print(MemoryLayout<SSLEnum>.size) print(MemoryLayout<SSLEnum2>.size) Print (MemoryLayout<SSLEnum3>. Size) print(MemoryLayout<SSLEnum4>. Size) The following output is displayed: 1 9 9 25Copy the code
- We can see from the output that when we have multiple loaded enumerations, the size of the enumeration depends on the size of the current maximum associated value
- If the number of bits required for the maximum correlation value is less than 8, and there is still room to represent all cases, the size of the enumeration is
1
- If the maximum associated value requires more than 8 bits, the size of the enumeration =
Maximum correlation value + 1
3.4 Special Cases
And then finally there’s a special case that we need to understand, so let’s look at the following case
enum SSLEnum {
case test_one
}
Copy the code
There is only one case for the current SSLEnum and we do not need anything to distinguish the current case, so when we print the current SSLEnum size you will find that it is 0.
Iv. Indirect keywords
Let’s look at the following error code:
Because enumerations are value types, the compile-time size is determined, and the associated value is an enumeration type, so there is no way to determine.
It is not a mistake to prefix the enumeration with an indirect, which assigns a BinaryTree to the heap space
Print the size of BinaryTree:
Print (MemoryLayout<BinaryTree<Int>>. SizeCopy the code
You can see that the sample size is 8 and is a reference type.
In addition to the enumeration, I can place an indirect before a case
enum BinaryTree<T> {
case empty(Int)
indirect case node(left: BinaryTree, value: T, right: BinaryTree)
}
Copy the code
At this point, not the entire enum is a reference type, only node is a reference type.
Five, the Optional
5.1 optional value
5.1.1 Understanding optional Values
We’ve already touched on optional values in our code. For example, we defined them in code like this:
class SSLTeacher {
var age: Int?
}
Copy the code
The current age is called the optional value, and of course the optional value is written the same as the following:
var age: Int?
var age: Optional<Int>
Copy the code
What is the nature of that for Optional? Let’s jump straight to the source and open the Optional. Swift file:
@frozen
public enum Optional<Wrapped>: ExpressibleByNilLiteral {
case none
case some(Wrapped)
}
Copy the code
Since Optional is essentially enumeration, we can make our own Optional modeled after the implementation of the system
enum MyOptional<Value> {
case some(Value)
case none
}
Copy the code
For example, given any natural number, return if the current natural number is even, nil otherwise, how should we express this case:
func getOddValue(_ value: Int) -> MyOptional<Int> {
if value & 2 == 0 {
return .some(value)
} else {
return .none
}
}
Copy the code
Given an array, we want to delete all the even numbers in the array:
At that point the compiler will check our current value and see that it doesn’t match the type the system compiler expects, so we can use MyOptional to limit syntax security.
Fetch the corresponding value through enum pattern matching:
var array = [1, 2, 3, 4, 5, 6]
for element in array {
let value = getOddValue(element)
switch value {
case .some(let value):
array.remove(at: array.firstIndex(of: value)!)
default:
print("value not exist")
}
}
Copy the code
If we change the above return value, we will use the system Optional
func getOddValue(_ value: Int) -> Int? {
if value & 2 == 0 {
return .some(value)
} else {
return .none
}
}
Copy the code
In this way, we are taking advantage of the current compiler’s type checking to achieve syntactic writing security.
5.1.2 the if the let
Of course, if every optional value is obtained by pattern matching, it would be tedious to write the code. We can also use the if let mode to bind the optional value:
if let value = value {
array.remove(at: array.firstIndex(of: value)!)
}
Copy the code
5.1.3 gurad let
In addition to using if lets to handle optional values, we can also use Gurad lets to simplify our code,
- Gurad let is the opposite of if let
- The Gurad let daemon must have some value. If not, return directly
- Usually judge if there is a value, will do a specific logical implementation, usually more code
Let’s look at a specific case:
let name: String? = "ssl" let age: Int? Guard let newName = name else {print(" name is empty ") return} Guard let newAge = age else {print(" age is empty ") return} // Print (newName + String(newAge))Copy the code
5.1.3 optional link chain
We know that in OC nothing happens when we send a message to a nil object, and in Swift we have no way of sending a message directly to a nil object, but we can achieve a similar effect with optional chains.
Let’s start with the following code
let str: String? = "abc" let upperStr = str? .upperstr () print(upperStr) // output: Optional<"ABC"> var str1: String? let upperStr1 = str1? .upperstr1 print(upperStr1) // outputs: nilCopy the code
So what does this code say
let str: String? = "ssl" let upperStr = str? .uppercased().lowerstr () print(upperStr) // output: Optional(" SSL ")Copy the code
The same optional chain applies to subscripts and function calls
var closure: ((Int) -> ())? closure? (1) // Closure for nil does not execute let dict: NSDictionary? = ["one": 1, "two": 2] print(dict? ["one"]) // Output: Optional(1) print(dict? ["three"]) // Output: nilCopy the code
5.2?? Operator (null merge operator)
( a ?? B) The optional type a is nullified and unpacked if a contains a value, otherwise a default value b is returned
- The expression a must be of type Optional
- The type of the default value B must be the same as the type of the value a stores
Look at the following example:
var age: Int? var x = age ?? Print (x)Copy the code
5.3 Operator overloading
In the source we can see that in addition to the overload?? Operator Optional also overloads ==,? = and so on. In practice, we can simplify our expressions by overloading the operators.
For example, if we define a two-dimensional vector in development and we want to perform basic operations on two vectors, we can override the operators to do so
extension Vector { static func + (fistVector: Vector, secondVector: Vector) -> Vector { return Vector(x: fistVector.x + secondVector.x, y: fistVector.y + secondVector.y) } static prefix func - (vector: Vector) -> Vector { return Vector(x: -vector.x, y: -vector.y) } static func - (fistVector: Vector, secondVector: Vector) -> Vector { return fistVector + -secondVector } } var v1 = Vector(x: 10, y: 20) var v2 = Vector(x: 20, y: 30) var v3 = v1 + v2 print(v3) var v4 = -v3 print(y: 50) var v3 = -v3 print(y: 50)Copy the code
We can also customize operators, as shown in the following example:
infix operator --- : AdditionPrecedence precedencegroup SSLPrecedence { lowerThan: AdditionPrecedence associativity: left } struct Vector { let x: Int let y: Int } extension Vector { static func --- (fistVector: Vector, secondVector: Vector) -> Vector { return Vector(x: fistVector.x * secondVector.x, y: fistVector.y * secondVector.y) } } var v1 = Vector(x: 10, y: 20) var v2 = Vector(x: 20, y: Print (x: 200, y: 600) print(x: 200, y: 600)Copy the code
For custom operators, check out the official documentation.
5.4 Implicit Resolution of Optional types
Implicit resolution of optional types is one type of optional type and is used in the same way as non-optional types. The only difference is that implicitly resolving the optional type tells the Swift compiler that the value will not be nil when accessed at runtime.
Take a look at the following sample code:
Age1 implicitly resolves optional types, so we don’t need to unpack it anymore, the compiler already does that for us.
If you run the project, you will find that there is no problem at compile time, but you will still get an error if there is no value: