There are two types of Swift language: named type and compound type. A named type is a type that can be given a name at definition. Named types include classes, structs, enumerations, and protocols. For example, an instance of a user-defined class MyClass has the type MyClass. In addition to user-defined named types, the Swift standard library defines many commonly used named types, including those representing arrays, dictionaries, and optional values.
Data types that are usually considered basic or elementary by other languages — such as representing numbers, characters, and strings — are actually named types, and the Swift standard library defines and implements them using constructs. 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.”
Compound types are nameless types defined by Swift itself. Swift has two compound types: function type and tuple type. 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 the 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.
Type syntax: Type and array -type | function -type | type – identifier | tuple -type | optional -type | implicitly – unwrapped – optional -type | protocol-composition-type | metatype-type
As a developer, it is particularly important to have a learning atmosphere and a communication circle. This is my iOS development public number: Programming Daxin, whether you are small white or big ox are welcome to enter. Let us progress together and develop together! (The group will provide some free study books collected by the group owner and hundreds of interview questions and answers documents for free!)
Type annotations
A type annotation explicitly specifies the value of a variable or expression. Type annotations begin with a colon: finally type, as 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 is specified as being of type (Double, Double). In the second example, the parameter a of the function someFunction is specified as an Int.
Type annotations can include an optional list of Type Attributes before the type.
Syntax for type annotations: type-annotation → :attributes[opt] type
Type identifier
A type identifier refers to a named type or an alias for a named/compound type.
In most cases, type identifiers refer to named types of the same name. For example, the type identifier Int refers to the named type Int, and similarly, the type identifier Dictionary<String, Int> refers to the named type Dictionary<String, Int>.
In both cases, type identifiers refer to types that do not have the same name. In case one, a type identifier refers to a type alias for a named/compound type. For example, in the following example, the type identifier uses Point to reference a tuple (Int, Int) :
1. typealias Point = (Int, Int)
2. let origin: Point = (0, 0)
Copy the code
Case two, the type identifier uses dot(.) Syntax to represent named types declared inside nested modules or other types. For example, the type identifier in the following example refers to the named type MyType declared in the ExampleModule module:
1. var someValue: ExampleModule.MyType
Copy the code
Syntax for type identifiers: Type – the identifier – type – the name generic argument – clause (opt) | type -name generic argument – clause [r]. Opt type – identifier Type – the name and identifier
A tuple type
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 to make it return multiple values. You can also name elements in tuple types and use those names to refer to the value of each element. The name of the element consists of an identifier and:. The section “Functions and Multiple Return Values” provides an example of these features.
Void is an alias for the empty tuple type (). If there is only one element inside the parentheses, the type is the type of the element inside the parentheses. For example, (Int) is of type Int instead of (Int). Therefore, you can mark tuple elements only if the tuple type contains more than two elements.
Tuple → (tuple-type-body[opt]) tuple-type-body → tuple-type-element-list… (opt) tuple -type element – the list – > element tuple – type – | the tuple – type – element, Tuple -type element – the list element tuple – type – – > attributes (opt) inout (opt) type | inout (opt) element – the name type – the annotation Element – the name and identifier
Function types
A function type represents the type of a function, method, or closure, consisting of a parameter type and a return value type separated by arrows -> parameter type -> return type
Since parameter types and return value types can be tuples, function types allow functions and methods to support multiple parameters and multiple return values.
You can apply an auto_closure property to a function type that takes an argument type () and returns an expression type (see type Properties section). An automatic closure function captures the 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
Function types can have a variable length argument as the last argument in the argument type. Syntactically, variable-length arguments consist of an underlying type name and… Composition, such as Int… . A variable length parameter is considered an array containing elements of the underlying type. The Int… Is an Int []. For an example of using variable length parameters, see the 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 the in-out Parameters section for a discussion of in-out parameters.
The type of a Curried function is equivalent to a nested function type. For example, the following Currization 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 corrified functions are grouped from right to left. For example, the function type Int -> Int -> Int can be understood as Int -> (Int -> Int) — that is, one function passes an Int and outputs it as input to another function, and then returns an Int. For example, you can override the Corrification function addTwoNumbers()() with the following nested function: addTwoNumbers()
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
An array type
The Swift language uses type names followed by brackets [] to simplify the named type Array defined in the standard 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 an array of strings. Array elements can also be accessed by [] : someArray[0] refers to the 0th element “Alex”.
The above example also shows that you can construct an array using [] as an initial value, and an empty [] is used to construct an empty array of the specified type.
1. var emptyArray: Double[] = []
Copy the code
You can also construct multi-dimensional arrays using multiple [] collections linked together. For example, the following example uses three [] sets 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 an element of a multidimensional array, the leftmost subscript points to the corresponding positional element of the outermost array. The next right subscript points to the corresponding position element embedded in the first layer, and so on. This means that, in the above example, array3D[0] refers to [[1, 2], [3, 4]], array3D[0][1] refers to [3, 4], and array3D[0][1] refers to the value 4.
For a detailed discussion of Array types in the Swift library, see the section Arrays.
An array type grammar: array – type – the type [] | array -type []
Optional type
Swift defines suffixes? Is short for the named type Optional defined in the standard 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. Notice the difference between type and? There is no space between.
The type Optional is an enumeration that takes two forms, None and Some(T), to represent values that may or may not be present. Any type can be explicitly declared (or implicitly converted) to an optional type. When declaring an optional type, be sure to use parentheses for? Provide a suitable scope of action. For example, to declare an optional array of integers, write (Int[])? , written as Int []? You’ll make a mistake.
If you do not provide an initial value when you declare or define an optional variable or feature, its value is automatically assigned to nil.
Optional Complies with the LogicValue protocol, so it can be used in a Boolean environment. At this point, if an optional type T? If the instance contains a value of type T (that is, optional.some (T)), this Optional type is true, otherwise 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! The operator gets an optional value of nil which causes a Runtime error.
You can also optionally perform operations on optional expressions using optional chains and optional bindings. If the value is nil, nothing is done so there is no run error.
For more details and more examples of how to use optional types, see the section “Optional.”
Optional type syntax: optional-type → type?
Implicitly resolves 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. Note the type vs.! There is no space between.
You can use implicit parsing optional where optional is used. For example, you can 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 feature, because it has a default value nil.
Since implicitly resolving optional values resolves automatically when used, there is no need to use operators! To parse it. That is, if you use an implicit parse option with a value of nil, it will cause a runtime error.
Using optional chains implicitly resolves an operation on an optional expression optionally. If the value is nil, nothing is done and therefore no run error is generated.
For more details on implicit parsing options, see the section “Implicit parsing Optional.”
Implicitly resolve optional syntax: IMPLICITLY -unwrapped-optional-type → type!
Protocol composition type
A protocol composition type is a specified protocol list type that matches each protocol. Protocol composition types may be used in type annotations and generic parameters.
Protocol < protocol 1, Procotol 2>
Protocol composite types allow you to specify a value whose type can be adapted to conditions of multiple protocols without defining a new named protocol to inherit from other protocols that you want to adapt to. For example, protocol< protocol A, protocol B, protocol C> is equivalent to A new protocol D inherited from Protocol A, protocol B, and Protocol C. This is obviously much more efficient, and doesn’t even require introducing a new name.
Each entry 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 protocol composite list so that each type fits.
Syntax for protocol composition types: Protocol – composition – type – protocol (protocol identifier – the list (opt) > protocol – identifier – the list – protocol – identifier | Protocol-identifier, protocol-identifier-list protocol-identifier → type-identifier
Yuan type
Meta-types are types of all types, including classes, structs, enumerations, and protocols.
The metatype of a class, structure, or enumeration type is immediately followed by the corresponding type name. The Type. The metatype of a protocol type — not the specific type that fits the protocol at runtime — follows the protocol name. Protocol. For example, the meta-type of class SomeClass is SomeClass.Type, and the meta-type of Protocol 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 SomeProtocol itself, rather than a runtime instance of some type that ADAPTS SomeProtocol. You can also use the dynamicType expression on an instance of a type to get the instance’s type at run time, as follows:
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 from and which protocols. The type inheritance clause begins with a colon:, followed by a list of type identifiers separated by a comma.
Classes can inherit from a single superclass for any number of protocols. When defining a class, the name of the superclass must appear at the top of the type identifier list, followed by any number of protocols that the class needs to adapt to. 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 the section “Inheritance.”
Other named types may inherit or adapt only a list of protocols. Protocol types 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 primitive values, a single named type specifying primitive value types. For an example of using a type inheritance clause to specify an enumeration definition of a primitive value type, see section “Primitive Values.”
Syntax for type inheritance clauses: Type – inheritance – clause – > : type – inheritance – the list type – inheritance – the list – type – identifier | type – identifier, type-inheritance-list
Type inference
Swift makes extensive use of type inference, which allows you to ignore the type or partial type of many variables and expressions. For example, for var x: Int = 0, you can omit the type entirely and simply write var x = 0 — the compiler will correctly infer that x is of type Int. Similarly, you can omit 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 infer that dict is Dictionary<String, Int>.
In the two examples above, type information is propagated from the leaf node of the Expression tree to the root node. That is, the type of x in var x: Int = 0 is first inferred from the type of 0, and that type information is then passed to the root node (variable x).
In Swift, type information can also flow in the opposite direction — from the root node to the leaf node. In the following example, the explicit type annotation (:Float) on the constant eFloat results in the number literal 2.71828 being of type Float instead of Double.
// The type of e is inferred to be Double. 2. Float = 2.71828 // The type of eFloat is Float.Copy the code
Type inference in Swift occurs at a separate expression or statement level. This means that all information used to infer a type must be available from type checking for an expression or one of its subexpressions.