The Swift language has two types: named types and compound types. A named type is a type that can be defined with a name. Named types include classes, structs, enumerations, and protocols. For example, an instance of a user-defined class MyClass has type MyClass. In addition to user-defined named types, the Swift library also defines a number of common named types, including those representing arrays, dictionaries, and optional values.
Data types that are often considered basic or elementary in other languages — such as representing numbers, characters, and strings — are actually named types, and the Swift library defines and implements them using structs. Because they are named types, you can declare an extension to increase their behavior to suit your program’s needs, as discussed in the section “Extensions and extension Declarations.”
A compound type is an unnamed type defined by Swift itself. There are two complex types of Swift: function types and tuple types. A compound type can contain named types and other compound types. For example, the tuple type (Int, (Int, Int)) contains two elements: the first is a named type Int, and the second is another compound type (Int, Int).
This section discusses the types defined by the Swift language itself and describes the type inference behavior in Swift.
Types of grammar: types – an array type | | | type identifier function type tuple type | | optional type implicit type an optional combination type | | agreement yuan type
Type annotations
Type annotations explicitly specify the value of a variable or expression. Type annotations start with a colon and end with a type, as shown in the following two examples:
1. Let someTuple (Double, Double) = (3.14159, 2.71828) 2. Func someFunction(a: Int){/*... * /}Copy the code
In the first example, the expression someTuple has the type (Double, Double) specified. In the second example, the type of the argument a to function someFunction is specified as Int.
A type annotation can precede a type with an optional list of Type attributes.
Syntax for type annotations: type-annotation → : attribute [OPT] type
Type identifier
Type identifiers refer to a named type or an alias for a named/compound type.
In most cases, the type identifier refers to a named type of the same name. For example, the type identifier Int refers to the named type Int. Similarly, the type identifier Dictionary<String, Int> refers to the named type Dictionary<String, Int>.
In both cases the type identifier does not refer to a type of the same name. In case one, the type identifier refers to a type alias of a named/compound type. For example, in the following example, the type identifier uses Point to refer to the tuple (Int, Int) :
1. typealias Point = (Int, Int)
2. let origin: Point = (0, 0)
Copy the code
In case two, the type identifier uses dot(.) Syntax to represent named types declared within a nest of other modules or other types. For example, in the following example, the type identifier refers to the named type MyType declared in ExampleModule:
1. var someValue: ExampleModule.MyType
Copy the code
Type identifier syntax: type identifier, type the name of the generic parameters clause (OPT) | type name generic parameter clause (OPT). Type identifier Type name → identifier
A tuple type
Tuple types are a list of zero or more types separated by commas and enclosed in parentheses.
You can use the tuple type as the return type of a function so that the function returns multiple values. You can also name the elements of a tuple type and use those names to refer to the values of each element. The name of an element consists of an identifier and:. An example of these features can be found in the “Functions and multiple return values” section.
Void is an alias for the empty tuple type (). If there is only one element in parentheses, then the type is the type of the element in parentheses. For example, (Int) is of type Int instead of (Int). Therefore, tuple elements can only be marked if the tuple type contains more than two elements.
Tuple type syntax:
Tuple →(tuple type body [opt]) Tuple type body → Tuple type element list… (opt) tuple TYPE elements – tuple element | tuple TYPE elements, yuan yuan TYPE elements group TYPE elements and attributes (opt) INOUT (opt) TYPE | INOUT (opt) element name TYPE – annotation element name and identifier
Function types
Function type represents the type of a function, method, or closure. It consists of a parameter type and a return value type separated by an arrow -> : parameter type -> return type
Because parameter types and return value types can be tuple types, function types allow functions and methods to support multiple arguments and multiple return values.
You can apply the auto_closure property to a function type with an argument type () and return the expression type (see the Type Properties section). An automatic closure function captures an implicit closure on a particular expression rather than the expression itself. The following example uses the auto_closure property to define a simple assert function:
1. func simpleAssert(condition: @auto_closure () -> Bool, message: String){ 2. if ! condition(){ 3. println(message) 4. } 5. } 6. let testNumber = 5 7. simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.") 8. // prints "testNumber isn't an even number."Copy the code
A function type can have a variable length argument as the last argument in the argument type. Syntactically, variable-length arguments consist of a base type name and… Consists of, for example, Int… . A variable-length argument is thought of as an array containing elements of the underlying type. The Int… Is an Int []. For an example of using variable-length parameters, see section “Variable-length parameters.”
To specify an in-out parameter, prefix the parameter type with inout. But you can’t use inout for variable length arguments or return value types. See section In-out Parameters for a discussion of in-out parameters.
The type of a Curried function is equivalent to a nested function type. For example, the following currie function addTwoNumber()() is of type Int -> Int -> Int:
1. func addTwoNumbers(a: Int)(b: Int) -> Int{
2. return a + b
3. }
4. addTwoNumbers(4)(5) // returns 9
Copy the code
The types of functions are grouped from right to left. For example, the function type Int -> Int -> Int can be understood as Int -> (Int -> Int) — that is, a function is passed an Int and output as input to another function, and then returns an Int. For example, you can override the curlization function addTwoNumbers()() with the following nested functions:
1. func addTwoNumbers(a: Int) -> (Int -> Int){
2. func addTheSecondNumber(b: Int) -> Int{
3. return a + b
4. }
5. return addTheSecondNumber
6. }
7. addTwoNumbers(4)(5) // Returns 9
Copy the code
Syntax for function types: function-type → type -> type
Data Collection Office
An array type
Swift uses the type name followed by brackets [] to simplify the named Array type defined in the library. In other words, the following two statements are equivalent:
1. let someArray: String[] = ["Alex", "Brian", "Dave"]
2. let someArray: Array<String> = ["Alex", "Brian", "Dave"]
Copy the code
In both cases, the constant someArray is declared as a string array. The elements of the array can also be accessed by [] : someArray[0] refers to the 0th element “Alex”.
The above example also shows that you can use [] as the initial value to construct an array, and the empty [] is used to construct an empty array of the specified type.
1. var emptyArray: Double[] = []
Copy the code
You can also construct multidimensional arrays using linked [] collections. For example, the following example uses three [] collections to construct a three-dimensional array of integers:
1. var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
Copy the code
When accessing the elements of a multidimensional array, the leftmost index points to the corresponding positional element in the outermost array. The next subscript to the right points to the corresponding positional elements embedded in the first layer, and so on. This means that, in the example above, array3D[0] is [[1, 2], [3, 4], array3D[0][1] is [3, 4], and array3D[0][1][1] is the value 4.
For a detailed discussion of Array types in the Swift standard library, see Section Arrays.
An array type grammar: array – type – the type [] | array -type []
Optional type
Swift definition suffix? As short for Optional, the named type defined in the library. In other words, the following two statements are equivalent:
1. var optionalInteger: Int?
2. var optionalInteger: Optional<Int>
Copy the code
In both cases, the variable optionalInteger is declared as an optionalInteger type. Note the differences in type and? There is no space between them.
Type Optional is an enumeration that has two forms, None and Some(T), to represent values that may or may not occur. Any type can be explicitly declared (or implicitly converted) as optional. When declaring an optional type, be sure to use parentheses for? Provide appropriate scope. For example, to declare an optional array of integers, write (Int[])? , written as Int []? If you do, you’ll get it wrong.
If you do not provide an initial value when declaring or defining an optional variable or property, its value is automatically assigned to the default value nil.
Optionally conforms to the LogicValue protocol, so it can appear in a Boolean value environment. Now, what if an optional type T? If the instance contains a value of type T (that is, the value is Optional.Some(T)), then the Optional type is true, otherwise it is false.
If an instance of an optional type contains a value, then you can use the postfix operator! To get the value, as described below:
1. optionalInteger = 42 2. optionalInteger! / / 42Copy the code
Use! Operator getting an option with a value of nil results in a Runtime error.
You can also use optional chains and optional bindings to selectively perform operations on optional expressions. If it’s nil, it doesn’t do anything so there’s no run error.
See section “Optional” for more details and more examples of how to use optional types.
Optional type syntax: optional-type → type?
Implicit parsing optional types
Swift language defines suffixes! As in the standard library named type ImplicitlyUnwrappedOptional shorthand. In other words, the following two statements are equivalent:
1. var implicitlyUnwrappedString: String!
2. var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>
Copy the code
These two cases, the variable implicitlyUnwrappedString is declared an implicit analytical optional types of string. Pay attention to type with! There is no space between them.
You can also use implicit parsing optional where you use optional. For example, you can assign implicitly resolve-optional values to variables, constants, and optional properties, and vice versa.
With optional, you don’t have to specify an initial value when you declare an implicit resolution optional variable or property, because it has the default value nil.
Since the implicit parsing of optional values is automatically resolved when used, there is no need to use an operator! To parse it. That is, if you use an implicit resolution option with a value of nil, it will cause a runtime error.
Using an optional chain optionally performs an operation on an implicit resolution of an optional expression. If the value is nil, nothing is done and therefore no runtime error occurs.
For more details on implicit parsing options, see section “Implicit Parsing Options.”
Implicitly parse optional syntax: implicitly-unwrapped-optional-type → type!
Protocol composition type
A protocol composition type is a specified protocol list type that conforms to each protocol. Protocol composition types may be used in type annotations and generic parameters.
The form of the protocol synthesis type is as follows: protocol< protocol 1, Procotol 2>
The protocol composition type allows you to specify a value whose type can fit multiple protocol conditions without defining a new named protocol that inherits from other protocols that you want to fit. For example, the protocol composition type protocol< protocol A, protocol B, protocol C> is equivalent to A new protocol D inherited from protocol A, protocol B, protocol C, It’s obviously much more efficient to do this, and you don’t even need to introduce a new name.
Each item in the protocol composition list must be a protocol name or a type alias of the protocol composition type. If the list is empty, it specifies an empty list of protocol compositions so that each type can fit.
Syntax of the protocol composition type: protocol – composition – type → Protocol protocol – identifier – list → Protocol identifier Protocol identifier, protocol identifier list Protocol identifier → type – identifier
Yuan type
A meta type is a type of all types, including classes, structs, enumerations, and protocols.
The metatype of a class, structure, or enumeration type is followed by the corresponding type name. The Type. The meta type of the protocol type — not the specific type that the runtime ADAPTS to the protocol — is what follows the protocol name. Protocol. For example, the metatype of SomeClass is someclass. Type, and the metatype of SomeProtocol is someprotocal.protocol.
You can use the suffix self expression to get the type. For example, SomeClass. Self returns SomeClass itself, not an instance of SomeClass. Similarly, someprotocol. self returns the SomeProtocol itself, not an instance of a type that the runtime ADAPTS to SomeProtocol. You can also use the dynamicType expression on an instance of a type to get the type of the instance at run time, as shown below:
1. class SomeBaseClass {
2. class func printClassName() {
3. println("SomeBaseClass")
4. }
5. }
6. class SomeSubClass: SomeBaseClass {
7. override class func printClassName() {
8. println("SomeSubClass")
9. }
10. }
11. let someInstance: SomeBaseClass = SomeSubClass()
12. // someInstance is of type SomeBaseClass at compile time, but
13. // someInstance is of type SomeSubClass at runtime
14. someInstance.dynamicType.printClassName()
15. // prints "SomeSubClass
Copy the code
Yuan types of grammar: metatype – type – the type. The type | the Protocol
Type inheritance clause
The type inheritance clause is used to specify which class a named type inherits and which protocols it is adapted to. The type inheritance clause starts with a colon: followed by a list of type identifiers separated by a colon:.
A class can inherit from a single superclass for any number of protocols. When defining a class, the name of the superclass must appear first in the list of type identifiers, followed by any number of protocols that the class needs to accommodate. If a class does not inherit from another class, the list can start with a protocol. For more discussion and examples of class inheritance, see section “Inheritance.”
Other named types may inherit or adapt to only one list of protocols. A protocol type may inherit from any number of other protocols. When a protocol type inherits from another protocol, the set of conditions for the other protocols is integrated, and then any other type inheriting from the current protocol must fit all of these conditions.
The type inheritance clause in an enumeration definition can be a list of protocols, or an enumeration specifying the primitive value, and a single named type specifying the primitive value type. See section “Primitive Values” for an example of an enumeration definition that uses the type inheritance clause to specify primitive value types.
Syntax for type inheritance clauses:
Type inheritance clause – > : inherit to the list types list – type identifier | type identifier, type list
Type inference
Swift makes extensive use of type inference, allowing you to ignore the type or partial type of many variables and expressions. For example, for var x: Int = 0, you can simply ignore the type completely and write var x = 0 — the compiler will correctly infer that x is of type Int. Similarly, you can ignore parts of a type when the full type can be inferred from the context. For example, if you write let dict: Dictionary = [“A”: 1], the compiler can also deduce that the dict type is Dictionary<String, Int>.
In both examples above, type information is passed from the leaf to the root of the Expression tree. That is, the type of x in var x: Int = 0 is first inferred from the type of 0, and then that type information is passed to the root node (variable x).
In Swift, type information can also flow in the opposite direction — from the root to the leaf. In the following example, an explicit type annotation (:Float) on the constant eFloat causes the numeric literal 2.71828 to be of type Float rather than Double.
2. What does The model say about e = 2.71828 // What does The model say about e? Float = 2.71828 // The type of eFloat is Float.Copy the code
Type inference in Swift takes place at the level of a separate expression or statement. This means that all information used to infer types must be available from type checking of the expression or one of its subexpressions.
Data Collection Office
Due to the limited space of the article, I can only briefly introduce some current work achievements and thoughts, and there are some new directions to explore in each Swift. If you are interested in the underlying principles, architecture design, system construction and how to interview of iOS, you can also follow me to get the latest information and information related to the interview. If you have any comments and suggestions, welcome to leave me a message!
The bad place that writes welcomes everybody to point out, hope everybody leaves a message to discuss more, let us progress together!
Those who like iOS can pay attention to me and study together!!
Link: www.jianshu.com/p/538bab3a3…