Although the swift language has now developed to the 2.0 version, but believe that many learning iOS development of children's shoes still have a wide range of Swift language questions, today's mini-series will give you a detailed introduction of the scope and interval in Swift, let's take a look at it.
Ranges
In the swift language, a range is expressed as a range type, and a scope is a collection of indexes.
It is worth noting that the range is used very frequently in the standard library, especially in the context of the collection. When we look at the range definition, the close relationship between the scope and the collection is at a glance:
struct range<element:forwardindextype>: CollectionType, indexable, ... {
...
}
Elements in a range must adhere to the Forwardindextype protocol, while a large number of functions in the Collecitontype protocol are also implemented based on it. There is a special type used to represent the scope of a collection index, which is quite meaningful for getting a subset of a collection. For example, we can use a range to get the parts of an array:
Let numbers = [1,2,3,4,5,6,7,8,9]
1..<5 equivalent to Range (Start:1, End:5)
NUMBERS[1..<5]//[2,3,4,5]
As seen in the definition of a type, range itself follows the CollectionType protocol, so that almost all the array can do, the scope can also be applied. For example, use a for loop to iterate through an element, or using contains (_:) Check to see if a value is within this range.
Although the scope is primarily intended for use with other collections, no one can prevent you from creating a range<int> that represents a range of numbers. After all, INT has implemented the Forwardindextype protocol. Now go back to the pattern matching issue.
We can use a range (int.min. <0). Contains (x) represents the case of x < 0, which is completely equivalent, but the execution speed is very slow. After all, the default is to traverse the entire collection, and in the worst case, it will be executed 9,223,372,036,854,775,808 times, which is quite resource-intensive. We can provide a better implementation for indexes of type comparable (such as INT):
Extension Range where element:comparable {
Func contains (element:element), Bool {
return element >= StartIndex && Element < EndIndex
}
}
(Int.min. <0). Contains ( -1)//True
(Int.min. <0). Contains (0)//False
(Int.min. <0). Contains (1)//False
This is a very good exercise, but in our case it is dispensable because the ~= operator's match for Range is efficient enough (like our contains (_:), comparable just works in the index). So we can do this:
Int.min. <0 ~=-1//True
Int.min. <0 ~= 0//False
Int.min. <0 ~= 1//False
On this basis, you can write a switch statement, using a range query to determine whether a number is greater than or equal to 0, right? Unfortunately, this does not apply. This piece of code will crash:
Let x = 10
Switch x {
Case 1...int.max://Exc_bad_instruction
Print ("positive")
Case Int.min. <0:
Print ("negative")
Case 0:
Print ("zero")
Default
FatalError ("should be unreachable")
}
We'll get a exc_bad_instruction error message in case 1...int.max that says "fatal Error:range End index has no valid successor". The cause of the error is that the EndIndex in range always points to the back of the last element in the range. This is for semi-open intervals (with.. < operator creation) and closing interval (with ... operator creation) is the same, because the internal implementation of the two is the same, a...b is actually a. <b.successor ().
It is important to remind you that a range<int> can never have int.max, which means that Int.max will never be a member of a range<int>, and this also applies to other types that have the largest value. This limitation does not allow the scope to meet our needs. So let's take a look at the interval that doesn't meet our requirements.
Interval
In fact, in swift, the scope and the interval are basically the same concept built (a series of sequential elements, with a beginning and ending), but different methods are used. The scope is index-based, so it can be a collection, and most of their functionality is essentially this feature. The interval is not a collection, their implementation is dependent on the comparable protocol. We can only create interval types for types that obey the comparable protocol:
Protocol Intervaltype {
Typealias bound:comparable
...
}
Unlike the definition of scope, the interval is presented using the INTERVALTYPE protocol, which has two specific implementations, Halfopeninterval and Closedinterval. The two range operators also provide overloads for the interval:. < Create a halfopeninterval and ... Create a closedinterval. Because the range is overloaded by default, you must explicitly define the variable as the interval type (intervaltype):
Let Int1:halfopeninterval = 1..<5
Int1.contains (5)//False
Let Int2:closedinterval = 1...5
Int2.contains (5)//True
It is important to note that Closedinterval cannot be empty, x...x always contains x, and x ... (x-1) can cause a run-time error.
However, a closed interval can contain the maximum value of a type. This means that we can now write our switch statement. Again, be sure to define the type and tell the compiler that we want the interval instead of the range:
Let x = 10
Switch x {
Case 1...int.max as Closedinterval:
Print ("positive")
Case Int.min. <0 as Halfopeninterval:
Print ("negative")
Case 0:
Print ("zero")
Default
FatalError ("should be unreachable")
}
Custom operator for open interval
What if you want to get rid of int.min and Int.max? At this point, you can customize the prefix operator and the suffix operator for open and closed intervals to represent all values that are less than one upper boundary, or that are greater than the value of a lower boundary. This is not only syntactically more friendly; Ideally, these operators apply not only to Int types, but also to other types that have minimum and maximum values. The implementation should look something like this:
Switch x {
Case 1 ...://an interval from 1 to Int.max (inclusive)
Print ("positive")
Case: <0://An interval from int.min to 0 (exclusive)
Print ("negative")
...
}
We need to do for. < and ... Defines how prefixes and suffixes are implemented separately. The following code is basically based on gist fragments written by Nate Cook.
First, we must declare the operator to be interpreted:
Prefix operator. < {}
Prefix operator ... { }
Postfix operator. < {}
Postfix operator ... { }
Immediately thereafter, the method of implementing the first operator for INT:
Forms a half-open interval from ' int.min ' to ' upperbound '
Prefix func. < (Upperbound:int), halfopeninterval<int> {
Return int.min. <upperbound
}
You can also make it more versatile. The interval requires that its underlying types follow the comparable protocol, so using the same conditional constraints is a natural choice. But here we have a problem: we need to know the minimum value of the T type to create the interval, but this does not have a common approach:
Prefix func. < <T:Comparable> (upperbound:t), halfopeninterval<t> {
Return t.min. <upperbound//Error:type ' T ' has no member ' min '
}
Even other protocols in the standard library do not provide these for numbers (for example, Integertype) – the min and Max attributes defined in the number type.
At this point, we can try this solution: Define a Minmaxtype custom protocol that defines the Min and Max two properties. Because all of the integer types have these two properties, let them follow the new protocol without having to write extra code:
Conforming types provide static ' Max ' and ' min ' constants.
Protocol Minmaxtype {
static Var min:self {get}
static Var max:self {get}
}
Extend Relevant types
Extension Int:minmaxtype {}
Extension Int8:minmaxtype {}
Extension Int16:minmaxtype {}
Extension Int32:minmaxtype {}
Extension Int64:minmaxtype {}
Extension Uint:minmaxtype {}
Extension Uint8:minmaxtype {}
Extension Uint16:minmaxtype {}
Extension Uint32:minmaxtype {}
Extension Uint64:minmaxtype {}
Here's a tip worth remembering. At any time, when you have several unrelated types, but they have one or more methods and properties of the same type, you can create a new protocol to provide them with a common interface.
Tell us the generic type T complies with the Minmaxtype protocol to enable this implementation to function properly:
Forms a half-open interval from ' t.min ' to ' upperbound '
Prefix func. < <t:comparable where t:minmaxtype>
(upperbound:t), halfopeninterval<t> {
Return t.min. <upperbound
}
Here is the implementation of the other three operators:
Forms a closed interval from ' t.min ' to ' upperbound '
Prefix func ... <t:comparable where t:minmaxtype>
(upperbound:t), closedinterval<t> {
Return T.min...upperbound
}
Forms a half-open interval from ' lowerbound ' to ' T.max '
Postfix func. < <t:comparable where t:minmaxtype>
(lowerbound:t), halfopeninterval<t> {
Return lowerbound. <t.max
}
Forms a closed interval from ' lowerbound ' to ' T.max '
Postfix func ... <t:comparable where t:minmaxtype>
(lowerbound:t), closedinterval<t> {
Return lowerbound ... T.max
}
Add some tests:
(.. <0). Contains (int.min)//True
(.. <0). Contains ( -1)//True
(.. <0). Contains (0)//False
(... 0). Contains (int.min)//True
(... 0). Contains (0)//True
(... 0). Contains (1)//False
(0..<). Contains ( -1)//False
(0..<). Contains (0)//True
(0..<). Contains (Int.max)//False
(0..<). Contains (int.max-1)//True
(0 ...). Contains ( -1)//False
(0 ...). Contains (0)//True
(0 ...). Contains (Int.max)//True
Back to our switch statement, it works well now:
Switch x {
Case 1 ...:
Print ("positive")
Case: <0:
Print ("negative")
Case 0:
Print ("zero")
Default
FatalError ("should be unreachable")
}
Conclusion
Swift has a similar purpose in scope and interval, but with different implementations and generic constraints. The scope is index-based and is often used in the context of a collection. This means that the range cannot contain a type maximum, which is not suitable for a number range. The interval is compatible with all comparable types, and there is no limit to the maximum value.
If you want to develop an iOS app in Swift language, the range and scope of these two concepts still need to be clear, understand when to use the scope, when to use the interval, improve development efficiency, improve the quality of code, step by step into the ranks of the iOS big God.
Related article: "Linux system CPU Usage query 5 common commands"
How are scopes and ranges used in Swift?