32.3. 基本表达式

基本表达式是最基本的表达式。它们可以单独使用,也可以跟前缀表达式、二元表达式、后缀表达式组合使用。

字面量表达式

字面量表达式 可由普通字面量(例如字符串或者数字),字典或者数组字面量,或者下面列表中的特殊字面量组成:

#file 表达式的值的格式是 module /filefile 是表达式所在的文件名,module 是文件所所在的模块名。#filePath 表达式的字符串值是表达式所在的文件在整个文件系统里的路径。所有这些值可以被 #sourceLocation 改变。

注意

要解析 #file 表达式,第一个斜杠(/)之前的文本作为模块名,最后一个斜杠之后的文本作为文件名。将来,该字符串可能包含多个斜杠,例如 MyModule/some/disambiguation/MyFile.swift

对于 #function,在函数中会返回当前函数的名字,在方法中会返回当前方法的名字,在属性的存取器中会返回属性的名字,在特殊的成员如 initsubscript 中会返回这个关键字的名字,在某个文件中会返回当前模块的名字。

当其作为函数或者方法的默认参数值时,该字面量的值取决于函数或方法的调用环境。

func logFunctionName(string: String = #function) {
    print(string)
}
func myFunction() {
    logFunctionName()
}
myFunction() // 打印“myFunction()”

数组字面量是值的有序集合,形式如下:[值 1, 值 2, ...]

数组中的最后一个表达式可以紧跟一个逗号。数组字面量的类型是 [T],这个 T 就是数组中元素的类型。如果数组中包含多种类型,T 则是跟这些类型最近的的公共父类型。空数组字面量由一组方括号定义,可用来创建特定类型的空数组。

var emptyArray: [Double] = []

字典字面量是一个包含无序键值对的集合,形式如下:[键 1 : 值 1, 键 2 : 值 2, ...]

字典中的最后一个表达式可以紧跟一个逗号。字典字面量的类型是 [Key : Value]Key 表示键的类型,Value 表示值的类型。如果字典中包含多种类型,那么 Key 表示的类型则为所有键最接近的公共父类型,Value 与之相似。一个空的字典字面量由方括号中加一个冒号组成([:]),从而与空数组字面量区分开,可以使用空字典字面量来创建特定类型的字典。

var emptyDictionary: [String : Double] = [:]

Xcode 使用 playground 字面量对程序编辑器中的颜色、文件或者图片创建可交互的展示。在 Xcode 之外的空白文本中,playground 字面量使用一种特殊的字面量语法来展示。

更多关于在 Xcode 中使用 playground 字面量的信息,请参阅 添加颜色、文件或图片字面量

字面量表达式语法

literal-expression

字面量表达式 → 字面量

字面量表达式 → 数组字面量 | 字典字面量 | 练习场字面量

字面量表达式#file#filePath | #line | #column | #function

array-literal

数组字面量 → [数组字面量项列表可选 ]

array-literal-items

数组字面量项列表 → 数组字面量项 , 可选 | 数组字面量项 , 数组字面量项列表

array-literal-item

数组字面量项 → 表达式

dictionary-literal

字典字面量 → [字典字面量项列表 ] | [ : ]

dictionary-literal-items

字典字面量项列表 → 字典字面量项 , 可选 | 字典字面量项 , 字典字面量项列表

dictionary-literal-item

字典字面量项 → 表达式 : 表达式。

playground-literal

playground 字面量#colorLiteral ( red : 表达式 , green :表达式 [表达式](#e表达式** xpression) , blue :表达式 , alpha : 表达式 )**

playground 字面量#fileLiteral ( resourceName : 表达式 )

playground 字面量* → #imageLiteral ( resourceName : 表达式 ) self-expression

Self 表达式

self 表达式是对当前类型或者当前实例的显式引用,它有如下形式:

  • self
  • self.成员名称
  • self[下标索引]
  • self(构造器参数)
  • self.init(构造器参数)

如果在构造器、下标、实例方法中,self 引用的是当前类型的实例。在一个类型方法中,self 引用的是当前的类型。

当访问成员时,self 可用来区分重名变量,例如函数的参数:

class SomeClass {
    var greeting: String
    init(greeting: String) {
        self.greeting = greeting
    }
}

mutating 方法中,你可以对 self 重新赋值:

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveByX(deltaX: Double, y deltaY: Double) {
        self = Point(x: x + deltaX, y: y + deltaY)
    }
}

Self 表达式语法

self-expression

self 表达式self | self 方法表达式 | self 下标表达式 | self 构造器表达式

self-method-expression

self 方法表达式self . 标识符

self-subscript-expression

self 下标表达式self [ 函数调用参数表 ]

self-initializer-expression

self 构造器表达式self . init

父类表达式

父类 表达式可以使我们在某个类中访问它的父类,它有如下形式:

  • super.成员名称
  • super[下标索引]
  • super.init(构造器参数)

第一种形式用来访问父类的某个成员,第二种形式用来访问父类的下标,第三种形式用来访问父类的构造器。

子类可以通过父类表达式在它们的成员、下标和构造器中使用父类中的实现。

父类表达式语法

superclass-expression

父类表达式 → 父类方法表达式 | 父类下标表达式 | 父类构造器表达式

superclass-method-expression

父类方法表达式super . 标识符

superclass-subscript-expression

父类下标表达式super [函数调用参数表 ]

superclass-initializer-expression

父类构造器表达式super . init

闭包表达式

闭包表达式 会创建一个闭包,在其他语言中也叫 lambda匿名 函数。跟函数一样,闭包包含了待执行的代码,不同的是闭包还会捕获所在环境中的常量和变量。它的形式如下:

{ (parameters) -> return type in
    statements
}

闭包的参数声明形式跟函数一样,请参阅 函数声明 。闭包还有几种特殊的形式,能让闭包使用起来更加简洁:

  • 闭包可以省略它的参数和返回值的类型。如果省略了参数名和所有的类型,也要省略 in 关键字。如果被省略的类型无法被编译器推断,那么就会导致编译错误。
  • 闭包可以省略参数名,参数会被隐式命名为 $ 加上其索引位置,例如 $0$1$2 分别表示第一个、第二个、第三个参数,以此类推。
  • 如果闭包中只包含一个表达式,那么该表达式的结果就会被视为闭包的返回值。表达式结果的类型也会被推断为闭包的返回类型。

下面几个闭包表达式是等价的:

myFunction {
    (x: Int, y: Int) -> Int in
    return x + y
}
myFunction {
    (x, y) in
    return x + y
}
myFunction { return $0 + $1 }
myFunction { $0 + $1 }

使用闭包表达式时,可以不必将其存储在一个变量或常量中,例如作为函数调用的一部分来立即使用一个闭包。在上面的例子中,传入 myFunction 的闭包表达式就是这种立即使用类型的闭包。因此,一个闭包是否逃逸与其使用时的上下文相关。一个会被立即调用或者作为函数的非逃逸参数传递的闭包表达式是非逃逸的,否则,这个闭包表达式是逃逸的。

关于逃逸闭包的内容,请参阅 8.6. 逃逸闭包