這里的教程為Swift官方教程中文版。

表達式(Expressions)


1.0 翻譯:sg552 校對:numbbbbb, stanzhai

2.0 翻譯+校對:EudeMorgen

2.1 翻譯:mmoaay

2.2 校對:175

3.0 翻譯+校對:chenmingjia

本頁包含內(nèi)容:

Swift 中存在四種表達式:前綴表達式,二元表達式,基本表達式和后綴表達式。表達式在返回一個值的同時還可以引發(fā)副作用。

通過前綴表達式和二元表達式可以對簡單表達式使用各種運算符?;颈磉_式從概念上講是最簡單的一種表達式,它是一種訪問值的方式。后綴表達式則允許你建立復(fù)雜的表達式,例如函數(shù)調(diào)用和成員訪問。每種表達式都在下面有詳細論述。

表達式語法
</a> 表達式try運算符可選 前綴表達式 二元表達式列表可選
表達式列表表達式 | 表達式 , 表達式列表

前綴表達式

前綴表達式由可選的前綴運算符和表達式組成。前綴運算符只接收一個參數(shù),表達式則緊隨其后。

關(guān)于這些運算符的更多信息,請參閱 基本運算符高級運算符。

關(guān)于 Swift 標準庫提供的運算符的更多信息,請參閱 Swift Standard Library Operators Reference。

除了標準庫運算符,你也可以對某個變量使用 & 運算符,從而將其傳遞給函數(shù)的輸入輸出參數(shù)。更多信息,請參閱 輸入輸出參數(shù)。

前綴表達式語法
</a> 前綴表達式前綴運算符可選 后綴表達式
前綴表達式輸入輸出表達式
輸入輸出表達式& 標識符

try 運算符

try 表達式由 try 運算符加上緊隨其后的可拋出錯誤的表達式組成,形式如下:

try 可拋出錯誤的表達式

可選的 try 表達式由 try? 運算符加上緊隨其后的可拋出錯誤的表達式組成,形式如下:

try? 可拋出錯誤的表達式

如果可拋出錯誤的表達式?jīng)]有拋出錯誤,整個表達式返回的可選值將包含可拋出錯誤的表達式的返回值,否則,該可選值為 nil

強制的 try 表達式由 try! 運算符加上緊隨其后的可拋出錯誤的表達式組成,形式如下:

try! 可拋出錯誤的表達式

如果可拋出錯誤的表達式拋出了錯誤,將會引發(fā)運行時錯誤。

在二進制運算符左側(cè)的表達式被標記上 trytry? 或者 try! 時,這個運算符對整個二進制表達式都產(chǎn)生作用。也就是說,你可以使用括號來明確運算符的作用范圍。

sum = try someThrowingFunction() + anotherThrowingFunction()   // try 對兩個函數(shù)調(diào)用都產(chǎn)生作用
sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 對兩個函數(shù)調(diào)用都產(chǎn)生作用
sum = (try someThrowingFunction()) + anotherThrowingFunction() // 錯誤:try 只對第一個函數(shù)調(diào)用產(chǎn)生作用

try 表達式不能出現(xiàn)在二進制運算符的的右側(cè),除非二進制運算符是賦值運算符或者 try 表達式是被圓括號括起來的。

關(guān)于 try、try?try! 的更多信息,以及該如何使用的例子,請參閱 錯誤處理。

try 表達式語法
try 運算符try | try? | try!

二元表達式

二元表達式由中綴運算符和左右參數(shù)表達式組成。形式如下:

左側(cè)參數(shù) 二元運算符 右側(cè)參數(shù)

關(guān)于這些運算符的更多信息,請參閱 基本運算符高級運算符。

關(guān)于 Swift 標準庫提供的運算符的更多信息,請參閱 Swift Standard Library Operators Reference。

注意
在解析時,一個二元表達式將作為一個扁平列表表示,然后根據(jù)運算符的優(yōu)先級,再進一步進行組合。例如,2 + 3 * 5 首先被看作具有五個元素的列表,即 2、+、3、*、5,隨后根據(jù)運算符優(yōu)先級組合為 (2 + (3 * 5))。

二元表達式語法
二元表達式二元運算符 前綴表達式
二元表達式賦值運算符 try運算符可選 前綴表達式
二元表達式條件運算符 try運算符可選 前綴表達式
二元表達式類型轉(zhuǎn)換運算符
二元表達式列表二元表達式 二元表達式列表可選

賦值表達式

賦值表達式會為某個給定的表達式賦值,形式如下;

表達式 =

右邊的值會被賦值給左邊的表達式。如果左邊表達式是一個元組,那么右邊必須是一個具有同樣元素個數(shù)的元組。(嵌套元組也是允許的。)右邊的值中的每一部分都會被賦值給左邊的表達式中的相應(yīng)部分。例如:

(a, _, (b, c)) = ("test", 9.45, (12, 3))
// a 為 "test",b 為 12,c 為 3,9.45 會被忽略

賦值運算符不返回任何值。

賦值運算符語法
賦值運算符=

三元條件運算符

三元條件運算符會根據(jù)條件來對兩個給定表達式中的一個進行求值,形式如下:

條件 ? 表達式(條件為真則使用) : 表達式(條件為假則使用)

如果條件為真,那么對第一個表達式進行求值并返回結(jié)果。否則,對第二個表達式進行求值并返回結(jié)果。未使用的表達式不會進行求值。

關(guān)于使用三元條件運算符的例子,請參閱 三元條件運算符。

三元條件運算符語法
三元條件運算符? try運算符可選 表達式 :

類型轉(zhuǎn)換運算符

有 4 種類型轉(zhuǎn)換運算符:is、as、as?as!。它們有如下的形式:

表達式 is 類型
表達式 as 類型
表達式 as? 類型
表達式 as! 類型

is 運算符在運行時檢查表達式能否向下轉(zhuǎn)化為指定的類型,如果可以則返回 ture,否則返回 false。

as 運算符在編譯時執(zhí)行向上轉(zhuǎn)換和橋接。向上轉(zhuǎn)換可將表達式轉(zhuǎn)換成超類的實例而無需使用任何中間變量。以下表達式是等價的:

func f(any: Any) { print("Function for Any") }
func f(int: Int) { print("Function for Int") }
let x = 10
f(x)
// 打印 “Function for Int”

let y: Any = x
f(y)
// 打印 “Function for Any”

f(x as Any)
// 打印 “Function for Any”

橋接可將 Swift 標準庫中的類型(例如 String)作為一個與之相關(guān)的 Foundation 類型(例如 NSString)來使用,而不需要新建一個實例。關(guān)于橋接的更多信息,請參閱 Using Swift with Cocoa and Objective-C (Swift2.2) 中的 Working with Cocoa Data Types。

as? 運算符有條件地執(zhí)行類型轉(zhuǎn)換,返回目標類型的可選值。在運行時,如果轉(zhuǎn)換成功,返回的可選值將包含轉(zhuǎn)換后的值,否則返回 nil。如果在編譯時就能確定轉(zhuǎn)換一定會成功或是失敗,則會導致編譯報錯。

as! 運算符執(zhí)行強制類型轉(zhuǎn)換,返回目標類型的非可選值。如果轉(zhuǎn)換失敗,則會導致運行時錯誤。表達式 x as! T 效果等同于 (x as? T)!。

關(guān)于類型轉(zhuǎn)換的更多內(nèi)容和例子,請參閱 類型轉(zhuǎn)換。

類型轉(zhuǎn)換運算符語法
類型轉(zhuǎn)換運算符is 類型
類型轉(zhuǎn)換運算符as 類型
類型轉(zhuǎn)換運算符as ? 類型
類型轉(zhuǎn)換運算符as ! 類型

基本表達式

基本表達式是最基本的表達式。它們可以單獨使用,也可以跟前綴表達式、二元表達式、后綴表達式組合使用。

基本表達式語法
基本表達式標識符 泛型實參子句可選
基本表達式字面量表達式
基本表達式self表達式
基本表達式超類表達式
基本表達式閉包表達式
基本表達式圓括號表達式
基本表達式隱式成員表達式
基本表達式通配符表達式
基本表達式選擇器表達式

字面量表達式

字面量表達式可由普通字面量(例如字符串或者數(shù)字),字典或者數(shù)組字面量,或者下面列表中的特殊字面量組成:

字面量 類型
#file String 所在的文件名
#line Int 所在的行數(shù)
#column Int 所在的列數(shù)
#function String 所在的聲明的名字

#line除了上述含義外,還有另一種含義。當它出現(xiàn)在單獨一行時,會被理解成行控制語句,請參閱線路控制語句

對于 #function,在函數(shù)中會返回當前函數(shù)的名字,在方法中會返回當前方法的名字,在屬性的存取器中會返回屬性的名字,在特殊的成員如 initsubscript 中會返回這個關(guān)鍵字的名字,在某個文件中會返回當前模塊的名字。

#function 作為函數(shù)或者方法的默認參數(shù)值時,該字面量的值取決于函數(shù)或方法的調(diào)用環(huán)境。

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

數(shù)組字面量是值的有序集合,形式如下:

[值 1, 值 2, ...]

數(shù)組中的最后一個表達式可以緊跟一個逗號。數(shù)組字面量的類型是 [T],這個 T 就是數(shù)組中元素的類型。如果數(shù)組中包含多種類型,T 則是跟這些類型最近的的公共父類型。空數(shù)組字面量由一組方括號定義,可用來創(chuàng)建特定類型的空數(shù)組。

var emptyArray: [Double] = []

字典字面量是一個包含無序鍵值對的集合,形式如下:

[鍵 1 : 值 1, 鍵 2 : 值 2, ...]

字典中的最后一個表達式可以緊跟一個逗號。字典字面量的類型是 [Key : Value],Key 表示鍵的類型,Value 表示值的類型。如果字典中包含多種類型,那么 Key 表示的類型則為所有鍵最接近的公共父類型,Value 與之相似。一個空的字典字面量由方括號中加一個冒號組成([:]),從而與空數(shù)組字面量區(qū)分開,可以使用空字典字面量來創(chuàng)建特定類型的字典。

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

字面量表達式語法

字面量表達式字面量
字面量表達式數(shù)組字面量 | 字典字面量
字面量表達式#file | #line | #column | #function

數(shù)組字面量[ 數(shù)組字面量項列表可選 ]
</a> 數(shù)組字面量項列表數(shù)組字面量項 ,可選 | 數(shù)組字面量項 , 數(shù)組字面量項列表
數(shù)組字面量項表達式

字典字面量[ 字典字面量項列表 ] | [ : ]
</a> 字典字面量項列表字典字面量項 ,可選 | 字典字面量項 , 字典字面量項列表
字典字面量項表達式 : 表達式

self 表達式

self 表達式是對當前類型或者當前實例的顯式引用,它有如下形式:

self
self.成員名稱
self[下標索引]
self(構(gòu)造器參數(shù))
self.init(構(gòu)造器參數(shù))

如果在構(gòu)造器、下標、實例方法中,self 引用的是當前類型的實例。在一個類型方法中,self 引用的是當前的類型。

當訪問成員時,self 可用來區(qū)分重名變量,例如函數(shù)的參數(shù):

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 表達式self | self 方法表達式self 下標表達式 | self 構(gòu)造器表達式

</a> self 方法表達式self . 標識符
self 下標表達式self [ 表達式 ] self 構(gòu)造器表達式self . init

超類表達式

超類表達式可以使我們在某個類中訪問它的超類,它有如下形式:

super.成員名稱
super[下標索引]
super.init(構(gòu)造器參數(shù))

第一種形式用來訪問超類的某個成員,第二種形式用來訪問超類的下標,第三種形式用來訪問超類的構(gòu)造器。

子類可以通過超類表達式在它們的成員、下標和構(gòu)造器中使用超類中的實現(xiàn)。

超類表達式語法
</a> 超類表達式超類方法表達式 | 超類下標表達式 | 超類構(gòu)造器表達式
超類方法表達式super . 標識符
</a> 超類下標表達式super [ 表達式 ]
超類構(gòu)造器表達式super . init

閉包表達式

閉包表達式會創(chuàng)建一個閉包,在其他語言中也叫 lambda 或匿名函數(shù)。跟函數(shù)一樣,閉包包含了待執(zhí)行的代碼,不同的是閉包還會捕獲所在環(huán)境中的常量和變量。它的形式如下:

{ (parameters) -> return type in  
    statements  
}

閉包的參數(shù)聲明形式跟函數(shù)一樣,請參閱 函數(shù)聲明。

閉包還有幾種特殊的形式,能讓閉包使用起來更加簡潔:

  • 閉包可以省略它的參數(shù)和返回值的類型。如果省略了參數(shù)名和所有的類型,也要省略 in 關(guān)鍵字。如果被省略的類型無法被編譯器推斷,那么就會導致編譯錯誤。
  • 閉包可以省略參數(shù)名,參數(shù)會被隱式命名為 $ 加上其索引位置,例如 $0、$1、$2 分別表示第一個、第二個、第三個參數(shù),以此類推。
  • 如果閉包中只包含一個表達式,那么該表達式的結(jié)果就會被視為閉包的返回值。表達式結(jié)果的類型也會被推斷為閉包的返回類型。

下面幾個閉包表達式是等價的:

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

myFunction {
    (x, y) in
    return x + y
}

myFunction { return $0 + $1 }

myFunction { $0 + $1 }

關(guān)于如何將閉包作為參數(shù)來傳遞的內(nèi)容,請參閱 函數(shù)調(diào)用表達式

捕獲列表

默認情況下,閉包會捕獲附近作用域中的常量和變量,并使用強引用指向它們。你可以通過一個捕獲列表來顯式指定它的捕獲行為。

捕獲列表在參數(shù)列表之前,由中括號括起來,里面是由逗號分隔的一系列表達式。一旦使用了捕獲列表,就必須使用 in 關(guān)鍵字,即使省略了參數(shù)名、參數(shù)類型和返回類型。

捕獲列表中的項會在閉包創(chuàng)建時被初始化。每一項都會用閉包附近作用域中的同名常量或者變量的值初始化。例如下面的代碼示例中,捕獲列表包含 a 而不包含 b,這將導致這兩個變量具有不同的行為。

var a = 0
var b = 0
let closure = { [a] in
    print(a, b)
}

a = 10
b = 10
closure()
// 打印 “0 10”

在示例中,變量 b 只有一個,然而,變量 a 有兩個,一個在閉包外,一個在閉包內(nèi)。閉包內(nèi)的變量 a 會在閉包創(chuàng)建時用閉包外的變量 a 的值來初始化,除此之外它們并無其他聯(lián)系。這意味著在閉包創(chuàng)建后,改變某個 a 的值都不會對另一個 a 的值造成任何影響。與此相反,閉包內(nèi)外都是同一個變量 b,因此在閉包外改變其值,閉包內(nèi)的值也會受影響。

如果閉包捕獲的值具有引用語義則有所不同。例如,下面示例中,有兩個變量 x,一個在閉包外,一個在閉包內(nèi),由于它們的值是引用語義,雖然這是兩個不同的變量,它們卻都引用著同一實例。

class SimpleClass {
    var value: Int = 0
}
var x = SimpleClass()
var y = SimpleClass()
let closure = { [x] in
    print(x.value, y.value)
}

x.value = 10
y.value = 10
closure()
// 打印 “10 10”

如果捕獲列表中的值是類類型,你可以使用 weak 或者 unowned 來修飾它,閉包會分別用弱引用和無主引用來捕獲該值。

myFunction { print(self.title) }                   // 以強引用捕獲
myFunction { [weak self] in print(self!.title) }   // 以弱引用捕獲
myFunction { [unowned self] in print(self.title) } // 以無主引用捕獲

在捕獲列表中,也可以將任意表達式的值綁定到一個常量上。該表達式會在閉包被創(chuàng)建時進行求值,閉包會按照指定的引用類型來捕獲表達式的值。例如:

// 以弱引用捕獲 self.parent 并賦值給 parent
myFunction { [weak parent = self.parent] in print(parent!.title) }

關(guān)于閉包表達式的更多信息和例子,請參閱 閉包表達式。關(guān)于捕獲列表的更多信息和例子,請參閱 解決閉包引起的循環(huán)強引用。

閉包表達式語法

閉包表達式{ 閉包簽名可選 語句 }

閉包簽名參數(shù)子句 函數(shù)結(jié)果可選 in
閉包簽名標識符列表 函數(shù)結(jié)果可選 in
閉包簽名捕獲列表 參數(shù)子句 函數(shù)結(jié)果可選 in
閉包簽名捕獲列表 標識符列表 函數(shù)結(jié)果可選 in
閉包簽名捕獲列表 in

捕獲列表[ 捕獲列表項列表 ]
</a> 捕獲列表項列表捕獲列表項 | 捕獲列表項 , 捕獲列表項列表
捕獲列表項捕獲說明符可選 表達式
捕獲說明符weak | unowned | unowned(safe) | unowned(unsafe)

隱式成員表達式

若類型可被推斷出來,可以使用隱式成員表達式來訪問某個類型的成員(例如某個枚舉成員或某個類型方法),形式如下:

.成員名稱

例如:

var x = MyEnumeration.SomeValue
x = .AnotherValue

隱式成員表達式語法
隱式成員表達式. 標識符

圓括號表達式

圓括號表達式由圓括號和其中多個逗號分隔的子表達式組成。每個子表達式前面可以有一個標識符,用冒號隔開。圓括號表達式形式如下:

(標識符 1 : 表達式 1, 標識符 2 : 表達式 2, ...)

使用圓括號表達式來創(chuàng)建元組,然后將其作為參數(shù)傳遞給函數(shù)。如果某個圓括號表達式中只有一個子表達式,那么它的類型就是子表達式的類型。例如,表達式 (1) 的類型是 Int,而不是 (Int)

圓括號表達式語法
</a> 圓括號表達式( 表達式元素列表可選 )
表達式元素列表表達式元素 | 表達式元素 , 表達式元素列表
表達式元素表達式 | 標識符 : 表達式

通配符表達式

通配符表達式可以在賦值過程中顯式忽略某個值。例如下面的代碼中,10 被賦值給 x,而 20 則被忽略:

(x, _) = (10, 20)
// x 為 10,20 被忽略

通配符表達式語法
通配符表達式_

選擇器表達式

選擇器表達式可以讓你通過選擇器來引用在Objective-C中方法(method)和屬性(property)的setter和getter方法。

#selector(方法名) #selector(getter: 屬性名) #selector(setter: 屬性名)

方法名和屬性名必須是存在于 Objective-C 運行時中的方法和屬性的引用。選擇器表達式的返回值是一個 Selector 類型的實例。例如:

class SomeClass: NSObject {
    let property: String
    @objc(doSomethingWithInt:)
    func doSomething(_ x: Int) { }

    init(property: String) {
        self.property = property
    }
}
let selectorForMethod = #selector(SomeClass.doSomething(_:))
let selectorForPropertyGetter = #selector(getter: SomeClass.property)

當為屬性的getter創(chuàng)建選擇器時,屬性名可以是變量屬性或者常量屬性的引用。但是當為屬性的setter創(chuàng)建選擇器時,屬性名只可以是對變量屬性的引用。

方法名稱可以包含圓括號來進行分組,并使用as 操作符來區(qū)分具有相同方法名但類型不同的方法, 例如:

extension SomeClass {
    @objc(doSomethingWithString:)
    func doSomething(_ x: String) { }
}
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)

由于選擇器是在編譯時創(chuàng)建的,因此編譯器可以檢查方法或者屬性是否存在,以及是否在運行時暴露給了 Objective-C 。

注意
雖然方法名或者屬性名是個表達式,但是它不會被求值。

更多關(guān)于如何在 Swift 代碼中使用選擇器來與 Objective-C API 進行交互的信息,請參閱 Using Swift with Cocoa and Objective-C (Swift 3)Objective-C Selectors部分。

選擇器表達式語法
選擇器表達式#selector ( 表達式 )
選擇器表達式#selector ( getter:表達式 )
選擇器表達式#selector ( setter:表達式 )

后綴表達式

后綴表達式就是在某個表達式的后面運用后綴運算符或其他后綴語法。從語法構(gòu)成上來看,基本表達式也是后綴表達式。

關(guān)于這些運算符的更多信息,請參閱 基本運算符高級運算符。

關(guān)于 Swift 標準庫提供的運算符的更多信息,請參閱 Swift Standard Library Operators Reference。

后綴表達式語法
后綴表達式基本表達式
后綴表達式后綴表達式 后綴運算符
后綴表達式函數(shù)調(diào)用表達式
后綴表達式構(gòu)造器表達式
后綴表達式顯式成員表達式
后綴表達式后綴 self 表達式
后綴表達式dynamicType 表達式
后綴表達式下標表達式
后綴表達式強制取值表達式
后綴表達式可選鏈表達式

函數(shù)調(diào)用表達式

函數(shù)調(diào)用表達式由函數(shù)名和參數(shù)列表組成,形式如下:

函數(shù)名(參數(shù) 1, 參數(shù) 2)

函數(shù)名可以是值為函數(shù)類型的任意表達式。

如果函數(shù)聲明中指定了參數(shù)的名字,那么在調(diào)用的時候也必須得寫出來。這種函數(shù)調(diào)用表達式具有以下形式:

函數(shù)名(參數(shù)名 1: 參數(shù) 1, 參數(shù)名 2: 參數(shù) 2)

如果函數(shù)的最后一個參數(shù)是函數(shù)類型,可以在函數(shù)調(diào)用表達式的尾部(右圓括號之后)加上一個閉包,該閉包會作為函數(shù)的最后一個參數(shù)。如下兩種寫法是等價的:

// someFunction 接受整數(shù)和閉包參數(shù)
someFunction(x, f: {$0 == 13})
someFunction(x) {$0 == 13}

如果閉包是該函數(shù)的唯一參數(shù),那么圓括號可以省略。

// someFunction 只接受一個閉包參數(shù)
myData.someMethod() {$0 == 13}
myData.someMethod {$0 == 13}

函數(shù)調(diào)用表達式語法
</a> 函數(shù)調(diào)用表達式后綴表達式 圓括號表達式
函數(shù)調(diào)用表達式后綴表達式 圓括號表達式可選 尾隨閉包
尾隨閉包閉包表達式

構(gòu)造器表達式

構(gòu)造器表達式用于訪問某個類型的構(gòu)造器,形式如下:

表達式.init(構(gòu)造器參數(shù))

你可以在函數(shù)調(diào)用表達式中使用構(gòu)造器表達式來初始化某個類型的新實例。也可以使用構(gòu)造器表達式來代理給超類構(gòu)造器。

class SomeSubClass: SomeSuperClass {
    override init() {
        // 此處為子類構(gòu)造過程
        super.init()
    }
}

和函數(shù)類似,構(gòu)造器表達式可以作為一個值。 例如:

// 類型注解是必須的,因為 String 類型有多種構(gòu)造器
let initializer: Int -> String = String.init
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +)
print(oneTwoThree)
// 打印 “123”

如果通過名字來指定某個類型,可以不用構(gòu)造器表達式而直接使用類型的構(gòu)造器。在其他情況下,你必須使用構(gòu)造器表達式。

let s1 = SomeType.init(data: 3) // 有效
let s2 = SomeType(data: 1)      // 有效

let s4 = someValue.dynamicType(data: 5)      // 錯誤
let s3 = someValue.dynamicType.init(data: 7) // 有效

構(gòu)造器表達式語法
構(gòu)造器表達式后綴表達式 . init
構(gòu)造器表達式后綴表達式 . init ( 參數(shù)名稱 )

顯式成員表達式

顯式成員表達式允許我們訪問命名類型、元組或者模塊的成員,其形式如下:

表達式.成員名

命名類型的某個成員在原始實現(xiàn)或者擴展中定義,例如:

class SomeClass {
    var someProperty = 42
}
let c = SomeClass()
let y = c.someProperty // 訪問成員

元組的成員會隱式地根據(jù)表示它們出現(xiàn)順序的整數(shù)來命名,以 0 開始,例如:

var t = (10, 20, 30)
t.0 = t.1
// 現(xiàn)在元組 t 為 (20, 20, 30)

對于模塊的成員來說,只能直接訪問頂級聲明中的成員。

為了區(qū)分只有參數(shù)名有所不同的方法或構(gòu)造器,在圓括號中寫出參數(shù)名,參數(shù)名后緊跟一個冒號,對于沒有參數(shù)名的參數(shù),使用下劃線代替參數(shù)名。而對于重載方法,則需使用類型標注進行區(qū)分。例如:

class SomeClass {
    func someMethod(x: Int, y: Int) {}
    func someMethod(x: Int, z: Int) {}
    func overloadedMethod(x: Int, y: Int) {}
    func overloadedMethod(x: Int, y: Bool) {}
}
let instance = SomeClass()

let a = instance.someMethod              // 有歧義
let b = instance.someMethod(_:y:)        // 無歧義

let d = instance.overloadedMethod        // 有歧義
let d = instance.overloadedMethod(_:y:)  // 有歧義
let d: (Int, Bool) -> Void  = instance.overloadedMethod(_:y:)  // 無歧義

如果點號(.)出現(xiàn)在行首,它會被視為顯式成員表達式的一部分,而不是隱式成員表達式的一部分。例如如下代碼所展示的被分為多行的鏈式方法調(diào)用:

let x = [10, 3, 20, 15, 4]
    .sort()
    .filter { $0 > 5 }
    .map { $0 * 100 }

顯式成員表達式語法
顯式成員表達式后綴表達式 . 十進制數(shù)字
顯式成員表達式后綴表達式 . 標識符 泛型實參子句可選
顯式成員表達式后綴表達式 . 標識符 ( 參數(shù)名稱 )

</a> 參數(shù)名稱參數(shù)名 參數(shù)名稱可選
參數(shù)名標識符 :

后綴 self 表達式

后綴 self 表達式由某個表達式或類型名緊跟 .self 組成,其形式如下:

表達式.self
類型.self

第一種形式返回表達式的值。例如:x.self 返回 x

第二種形式返回相應(yīng)的類型。我們可以用它來獲取某個實例的類型作為一個值來使用。例如,SomeClass.self 會返回 SomeClass 類型本身,你可以將其傳遞給相應(yīng)函數(shù)或者方法作為參數(shù)。

后綴 self 表達式語法
后綴 self 表達式后綴表達式 . self

dynamicType 表達式

dynamicType 表達式由類似函數(shù)調(diào)用表達式(Function Call Expression)的特殊語法表達式組成,形式如下:

type(of:表達式)

上述形式中的表達式不能是類型名。type(of:) 表達式會返回某個實例在運行時的類型,具體請看下面的例子:

class SomeBaseClass {
    class func printClassName() {
        print("SomeBaseClass")
    }
}
class SomeSubClass: SomeBaseClass {
    override class func printClassName() {
        print("SomeSubClass")
    }
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在編譯時的靜態(tài)類型為 SomeBaseClass,
// 在運行時的動態(tài)類型為 SomeSubClass
type(of: someInstance).printClassName()
// 打印 “SomeSubClass”

動態(tài)類型表達式語法
動態(tài)類型表達式 → type(of:表達式) . dynamicType

下標表達式

可通過下標表達式訪問相應(yīng)的下標,形式如下:

表達式[索引表達式]

要獲取下標表達式的值,可將索引表達式作為下標表達式的參數(shù)來調(diào)用下標 getter。下標 setter 的調(diào)用方式與之一樣。

關(guān)于下標的聲明,請參閱 協(xié)議下標聲明。

下標表達式語法
下標表達式后綴表達式 [ 表達式列表 ]

強制取值表達式

當你確定可選值不是 nil 時,可以使用強制取值表達式來強制解包,形式如下:

表達式!

如果該表達式的值不是 nil,則返回解包后的值。否則,拋出運行時錯誤。

返回的值可以被修改,無論是修改值本身,還是修改值的成員。例如:

var x: Int? = 0
x!++
// x 現(xiàn)在是 1

var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
someDictionary["a"]![0] = 100
// someDictionary 現(xiàn)在是 [b: [10, 20], a: [100, 2, 3]]

強制取值語法
強制取值表達式后綴表達式 !

可選鏈表達式

可選鏈表達式提供了一種使用可選值的便捷方法,形式如下:

表達式?

后綴 ? 運算符會根據(jù)表達式生成可選鏈表達式而不會改變表達式的值。

如果某個后綴表達式包含可選鏈表達式,那么它的執(zhí)行過程會比較特殊。如果該可選鏈表達式的值是 nil,整個后綴表達式會直接返回 nil。如果該可選鏈表達式的值不是 nil,則返回可選鏈表達式解包后的值,并將該值用于后綴表達式中剩余的表達式。在這兩種情況下,整個后綴表達式的值都會是可選類型。

如果某個后綴表達式中包含了可選鏈表達式,那么只有最外層的表達式會返回一個可選類型。例如,在下面的例子中,如果 c 不是 nil,那么它的值會被解包,然后通過 .property 訪問它的屬性,接著進一步通過 .performAction() 調(diào)用相應(yīng)方法。整個 c?.property.performAction() 表達式返回一個可選類型的值,而不是多重可選類型。

var c: SomeClass?
var result: Bool? = c?.property.performAction()

上面的例子跟下面的不使用可選鏈表達式的例子等價:

var result: Bool? = nil
if let unwrappedC = c {
    result = unwrappedC.property.performAction()
}

可選鏈表達式解包后的值可以被修改,無論是修改值本身,還是修改值的成員。如果可選鏈表達式的值為 nil,則表達式右側(cè)的賦值操作不會被執(zhí)行。例如:

func someFunctionWithSideEffects() -> Int {
    // 譯者注:為了能看出此函數(shù)是否被執(zhí)行,加上了一句打印
    print("someFunctionWithSideEffects") 
    return 42 
}
var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]

someDictionary["not here"]?[0] = someFunctionWithSideEffects()
// someFunctionWithSideEffects 不會被執(zhí)行
// someDictionary 依然是 ["b": [10, 20], "a": [1, 2, 3]]

someDictionary["a"]?[0] = someFunctionWithSideEffects()
// someFunctionWithSideEffects 被執(zhí)行并返回 42
// someDictionary 現(xiàn)在是 ["b": [10, 20], "a": [42, 2, 3]]

可選鏈表達式語法
可選鏈表達式后綴表達式 ?

? 類型 語句 ?
?