本页包括内容:
类型注解(Type Annotation)
类型标识符(Type Identifier)
元组类型(Tuple Type)
函数类型(Function Type)
数组类型(Array Type)
可选类型(Optional Type)
隐式解析可选类型(Implicitly Unwrapped Optional Type)
协议合成类型(Protocol Composition Type)
元类型(Metatype Type)
类型继承子句(Type Inheritance Clause)
类型判断(Type Inference)
Swift 语言存在两种类型:命名型类型和复合型类型。
命名型类型是指定义时能够给定名字的类型。命名型类型包括类、结构体、枚举和协议。比方,一个用户定义的类MyClass的实例拥有类型MyClass。
除了用户定义的命名型类型,Swift 标准库也定义了非常多经常使用的命名型类型,包括那些表示数组、字典和可选值的类型。
那些通常被其他语言觉得是基本或0基础的数据型类型(Data types)——比方表示数字、字符和字符串——实际上就是命名型类型,Swift 标准库是使用结构体定义和实现它们的。由于它们是命名型类型,因此你能够依照“扩展和扩展声明”章节里讨论的那样,声明一个扩展来添加它们的行为以适应你程序的需求。
复合型类型是没有名字的类型。它由 Swift 本身定义。Swift 存在两种复合型类型:函数类型和元组类型。一个复合型类型能够包括命名型类型和其他复合型类型。比如,元组类型(Int, (Int, Int))包括两个元素:第一个是命名型类型Int。第二个是还有一个复合型类型(Int, Int).
本节讨论 Swift 语言本身定义的类型,并描写叙述 Swift 中的类型判断行为。
类型的语法:
type → array-type | function-type | type-identifier | tuple-type | optional-type | implicitly-unwrapped-optional-type | protocol-composition-type | metatype-type
类型注解
类型注解显式地指定一个变量或表达式的值。类型注解始于冒号:最终类型,比方以下两个样例:
- let someTuple:(Double, Double) = (3.14159, 2.71828)
- func someFunction(a: Int){ /* ... */ }
在第一个样例中。表达式someTuple的类型被指定为(Double, Double)。在第二个样例中。函数someFunction的參数a的类型被指定为Int。
类型注解能够在类型之前包括一个类型特性(type attributes)的可选列表。
类型注解的语法: type-annotation → :
attributesopttype
类型标识符
类型标识符引用命名型类型或者是命名型/复合型类型的别名。
大多数情况下。类型标识符引用的是同名的命名型类型。比如类型标识符Int引用命名型类型Int。相同。类型标识符Dictionary<String, Int>引用命名型类型Dictionary<String, Int>。
在两种情况下类型标识符引用的不是同名的类型。情况一。类型标识符引用的是命名型/复合型类型的类型别名。比方。在以下的样例中,类型标识符使用Point来引用元组(Int, Int):
- typealias Point = (Int, Int)
- let origin: Point = (0, 0)
情况二,类型标识符使用dot(.)语法来表示在其他模块(modules)或其他类型嵌套内声明的命名型类型。比如。以下样例中的类型标识符引用在ExampleModule模块中声明的命名型类型MyType:
- var someValue: ExampleModule.MyType
类型标识符的语法:
type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-clauseopt.
type-identifier
type-name → identifier
元组类型
元组类型使用逗号隔开并使用括号括起来的0个或多个类型组成的列表。
你能够使用元组类型作为一个函数的返回类型。这样就能够使函数返回多个值。你也能够命名元组类型中的元素,然后用这些名字来引用每一个元素的值。元素的名字由一个标识符和:组成。“函数和多返回值”章节里有一个展示上述特性的样例。
void是空元组类型()的别名。假设括号内仅仅有一个元素,那么该类型就是括号内元素的类型。
比方。(Int)的类型是Int而不是(Int)。所以,仅仅有当元组类型包括两个元素以上时才干够标记元组元素。
元组类型语法:
tuple-type → (
tuple-type-bodyopt)
tuple-type-body → tuple-type-element-list...
opt
tuple-type-element-list → tuple-type-element tuple-type-element,
tuple-type-element-list
tuple-type-element → attributesoptinout
opttype inout
optelement-nametype-annotation
element-name → identifier
函数类型
函数类型表示一个函数、方法或闭包的类型,它由一个參数类型和返回值类型组成。中间用箭头->隔开:
- parameter type -> return type
由于 參数类型 和 返回值类型 能够是元组类型。所以函数类型能够让函数与方法支持多參数与多返回值。
你能够对函数类型应用带有參数类型()并返回表达式类型的auto_closure属性(见类型属性章节)。一个自己主动闭包函数捕获特定表达式上的隐式闭包而非表达式本身。以下的样例使用auto_closure属性来定义一个非常easy的assert函数:
- func simpleAssert(condition: @auto_closure () -> Bool, message: String){
- if !condition(){
- println(message)
- }
- }
- let testNumber = 5
- simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")
- // prints "testNumber isn't an even number."
函数类型能够拥有一个可变长參数作为參数类型中的最后一个參数。从语法角度上讲,可变长參数由一个基础类型名字和...组成,如Int...。可变长參数被觉得是一个包括了基础类型元素的数组。即Int...就是Int[]。关于使用可变长參数的样例。见章节“可变长參数”。
为了指定一个in-out參数,能够在參数类型前加inout前缀。
可是你不能够对可变长參数或返回值类型使用inout。关于In-Out參数的讨论见章节In-Out參数部分。
柯里化函数(curried function)的类型相当于一个嵌套函数类型。
比如,以下的柯里化函数addTwoNumber()()的类型是Int -> Int -> Int:
- func addTwoNumbers(a: Int)(b: Int) -> Int{
- return a + b
- }
- addTwoNumbers(4)(5) // returns 9
柯里化函数的函数类型从右向左组成一组。
比如,函数类型Int -> Int -> Int能够被理解为Int -> (Int -> Int)——也就是说。一个函数传入一个Int然后输出作为还有一个函数的输入。然后又返回一个Int。
比如。你能够使用例如以下嵌套函数来重写柯里化函数addTwoNumbers()():
- func addTwoNumbers(a: Int) -> (Int -> Int){
- func addTheSecondNumber(b: Int) -> Int{
- return a + b
- }
- return addTheSecondNumber
- }
- addTwoNumbers(4)(5) // Returns 9
函数类型的语法:
数组类型
Swift语言使用类型名紧接中括号[]来简化标准库中定义的命名型类型Array<T>。换句话说,以下两个声明是等价的:
- let someArray: String[] = ["Alex", "Brian", "Dave"]
- let someArray: Array<String> = ["Alex", "Brian", "Dave"]
上面两种情况下,常量someArray都被声明为字符串数组。数组的元素也能够通过[]获取訪问:someArray[0]是指第0个元素“Alex”。
上面的样例同一时候显示。你能够使用[]作为初始值构造数组,空的[]则用来来构造指定类型的空数组。
- var emptyArray: Double[] = []
你也能够使用链接起来的多个[]集合来构造多维数组。比如。下例使用三个[]集合来构造三维整型数组:
- var array3D: Int[][][] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
訪问一个多维数组的元素时。最左边的下标指向最外层数组的对应位置元素。接下来往右的下标指向第一层嵌入的对应位置元素。依次类推。这就意味着,在上面的样例中,array3D[0]是指[[1, 2], [3, 4]],array3D[0][1]是指[3, 4]。array3D[0][1][1]则是指值4。
关于Swift标准库中Array类型的细节讨论。见章节Arrays。
数组类型的语法:array-type → type[]
array-type[]
可选类型
Swift定义后缀?
来作为标准库中的定义的命名型类型Optional<T>的简写。换句话说,以下两个声明是等价的:
- var optionalInteger: Int?
- var optionalInteger: Optional<Int>
在上述两种情况下,变量optionalInteger都被声明为可选整型类型。注意在类型和?之间没有空格。
类型Optional<T>是一个枚举,有两种形式,None和Some(T),又来代表可能出现或可能不出现的值。随意类型都能够被显式的声明(或隐式的转换)为可选类型。
当声明一个可选类型时。确保使用括号给?提供合适的作用范围。比方说。声明一个整型的可选数组,应写作(Int[])?。写成Int[]?的话则会出错。
假设你在声明或定义可选变量或特性的时候没有提供初始值,它的值则会自己主动赋成缺省值nil。
可选符合LogicValue协议,因此能够出如今布尔值环境下。
此时。假设一个可选类型T?
实例包括有类型为T的值(也就是说值为Optional.Some(T)),那么此可选类型就为true,否则为false。
假设一个可选类型的实例包括一个值,那么你就能够使用后缀操作符!来获取该值,正如以下描写叙述的:
- optionalInteger = 42
- optionalInteger! // 42
使用!操作符获取值为nil的可选项会导致执行错误(runtime error)。
你也能够使用可选链和可选绑定来选择性的执行可选表达式上的操作。
假设值为nil,不会执行不论什么操作因此也就没有执行错误产生。
很多其他细节以及很多其他怎样使用可选类型的样例,见章节“可选”。
可选类型语法:optional-type → type?
隐式解析可选类型
Swift语言定义后缀!作为标准库中命名类型ImplicitlyUnwrappedOptional<T>的简写。换句话说,以下两个声明等价:
- var implicitlyUnwrappedString: String!
- var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>
上述两种情况下,变量implicitlyUnwrappedString被声明为一个隐式解析可选类型的字符串。注意类型与!之间没有空格。
你能够在使用可选的地方相同使用隐式解析可选。比方,你能够将隐式解析可选的值赋给变量、常量和可选特性,反之亦然。
有了可选,你在声明隐式解析可选变量或特性的时候就不用指定初始值。由于它有缺省值nil。
由于隐式解析可选的值会在使用时自己主动解析,所以不是必需使用操作符!来解析它。也就是说,假设你使用值为nil的隐式解析可选,就会导致执行错误。
使用可选链会选择性的执行隐式解析可选表达式上的某一个操作。
假设值为nil,就不会执行不论什么操作,因此也不会产生执行错误。
关于隐式解析可选的很多其他细节,见章节“隐式解析可选”。
隐式解析可选的语法:implicitly-unwrapped-optional-type → type!
协议合成类型
协议合成类型是一种符合每一个协议的指定协议列表类型。协议合成类型可能会用在类型注解和泛型參数中。
协议合成类型的形式例如以下:
- protocol<Protocol 1, Procotol 2>
协议合成类型同意你指定一个值,其类型能够适配多个协议的条件。并且不须要定义一个新的命名型协议来继承其他想要适配的各个协议。
比方,协议合成类型protocol<Protocol A, Protocol B, Protocol C>等效于一个从Protocol A,Protocol B, Protocol C继承而来的新协议Protocol D,非常显然这样做有效率的多,甚至不需引入一个新名字。
协议合成列表中的每项必须是协议名或协议合成类型的类型别名。
假设列表为空。它就会指定一个空协议合成列表。这样每一个类型都能适配。
协议合成类型的语法:
protocol-composition-type → protocol<
protocol-identifier-listopt>
protocol-identifier-list → protocol-identifier protocol-identifier,
protocol-identifier-list
protocol-identifier → type-identifier
元类型
元类型是指全部类型的类型,包括类、结构体、枚举和协议。
类、结构体或枚举类型的元类型是对应的类型名紧跟.Type。协议类型的元类型——并非执行时适配该协议的详细类型——是该协议名字紧跟.Protocol。
比方,类SomeClass的元类型就是SomeClass.Type,协议SomeProtocol的元类型就是SomeProtocal.Protocol。
你能够使用后缀self表达式来获取类型。
比方。SomeClass.self返回SomeClass本身。而不是SomeClass的一个实例。
相同,SomeProtocol.self返回SomeProtocol本身,而不是执行时适配SomeProtocol的某个类型的实例。
还能够对类型的实例使用dynamicType表达式来获取该实例在执行阶段的类型,例如以下所看到的:
- class SomeBaseClass {
- class func printClassName() {
- println("SomeBaseClass")
- }
- }
- class SomeSubClass: SomeBaseClass {
- override class func printClassName() {
- println("SomeSubClass")
- }
- }
- let someInstance: SomeBaseClass = SomeSubClass()
- // someInstance is of type SomeBaseClass at compile time, but
- // someInstance is of type SomeSubClass at runtime
- someInstance.dynamicType.printClassName()
- // prints "SomeSubClass
元类型的语法: metatype-type → type.Type
type.Protocol
类型继承子句
类型继承子句被用来指定一个命名型类型继承哪个类且适配哪些协议。
类型继承子句開始于冒号:。紧跟由,隔开的类型标识符列表。
类能够继承单个超类,适配随意数量的协议。
当定义一个类时,超类的名字必须出如今类型标识符列表首位。然后跟上该类须要适配的随意数量的协议。假设一个类不是从其他类继承而来,那么列表能够以协议开头。关于类继承很多其他的讨论和样例,见章节“继承”。
其他命名型类型可能仅仅继承或适配一个协议列表。协议类型可能继承于其他随意数量的协议。
当一个协议类型继承于其他协议时,其他协议的条件集合会被集成在一起,然后其他从当前协议继承的随意类型必须适配全部这些条件。
枚举定义中的类型继承子句能够是一个协议列表,或是指定原始值的枚举,一个单独的指定原始值类型的命名型类型。使用类型继承子句来指定原始值类型的枚举定义的样例,见章节“原始值”。
类型继承子句的语法:
type-inheritance-clause → :
type-inheritance-list
type-inheritance-list → type-identifier type-identifier,
type-inheritance-list
类型判断
Swift广泛的使用类型判断,从而同意你能够忽略非常多变量和表达式的类型或部分类型。比方,对于var x: Int = 0,你能够全然忽略类型而简写成var x = 0——编译器会正确的判断出x的类型Int。
相似的,当完整的类型能够从上下文判断出来时,你也能够忽略类型的一部分。比方,假设你写了let dict: Dictionary = ["A": 1],编译提也能判断出dict的类型是Dictionary<String, Int>。
在上面的两个样例中。类型信息从表达式树(expression tree)的叶子节点传向根节点。也就是说,var x: Int = 0中x的类型首先依据0的类型进行判断,然后将该类型信息传递到根节点(变量x)。
在Swift中,类型信息也能够反方向流动——从根节点传向叶子节点。在以下的样例中。常量eFloat上的显式类型注解(:Float)导致数字字面量2.71828的类型是Float而非Double。
- let e = 2.71828 // The type of e is inferred to be Double.
- let eFloat: Float = 2.71828 // The type of eFloat is Float.
Swift中的类型判断在单独的表达式或语句水平上进行。这意味着全部用于判断类型的信息必须能够从表达式或其某个子表达式的类型检查中获取。