1.0 翻譯:sg552 校對(duì):numbbbbb, stanzhai
2.0 翻譯+校對(duì):EudeMorgen
2.1 翻譯:mmoaay
2.2 校對(duì):175
3.0 翻譯+校對(duì):chenmingjia
本頁包含內(nèi)容:
Swift 中存在四種表達(dá)式:前綴表達(dá)式,二元表達(dá)式,基本表達(dá)式和后綴表達(dá)式。表達(dá)式在返回一個(gè)值的同時(shí)還可以引發(fā)副作用。
通過前綴表達(dá)式和二元表達(dá)式可以對(duì)簡單表達(dá)式使用各種運(yùn)算符?;颈磉_(dá)式從概念上講是最簡單的一種表達(dá)式,它是一種訪問值的方式。后綴表達(dá)式則允許你建立復(fù)雜的表達(dá)式,例如函數(shù)調(diào)用和成員訪問。每種表達(dá)式都在下面有詳細(xì)論述。
表達(dá)式語法
</a> 表達(dá)式 → try運(yùn)算符可選 前綴表達(dá)式 二元表達(dá)式列表可選
表達(dá)式列表 → 表達(dá)式 | 表達(dá)式 , 表達(dá)式列表
前綴表達(dá)式由可選的前綴運(yùn)算符和表達(dá)式組成。前綴運(yùn)算符只接收一個(gè)參數(shù),表達(dá)式則緊隨其后。
關(guān)于這些運(yùn)算符的更多信息,請參閱 基本運(yùn)算符 和 高級(jí)運(yùn)算符。
關(guān)于 Swift 標(biāo)準(zhǔn)庫提供的運(yùn)算符的更多信息,請參閱 Swift Standard Library Operators Reference。
除了標(biāo)準(zhǔn)庫運(yùn)算符,你也可以對(duì)某個(gè)變量使用 &
運(yùn)算符,從而將其傳遞給函數(shù)的輸入輸出參數(shù)。更多信息,請參閱 輸入輸出參數(shù)。
前綴表達(dá)式語法
</a> 前綴表達(dá)式 → 前綴運(yùn)算符可選 后綴表達(dá)式
前綴表達(dá)式 → 輸入輸出表達(dá)式
輸入輸出表達(dá)式 → & 標(biāo)識(shí)符
try 表達(dá)式由 try
運(yùn)算符加上緊隨其后的可拋出錯(cuò)誤的表達(dá)式組成,形式如下:
try
可拋出錯(cuò)誤的表達(dá)式
可選的 try 表達(dá)式由 try?
運(yùn)算符加上緊隨其后的可拋出錯(cuò)誤的表達(dá)式組成,形式如下:
try?
可拋出錯(cuò)誤的表達(dá)式
如果可拋出錯(cuò)誤的表達(dá)式?jīng)]有拋出錯(cuò)誤,整個(gè)表達(dá)式返回的可選值將包含可拋出錯(cuò)誤的表達(dá)式的返回值,否則,該可選值為 nil
。
強(qiáng)制的 try 表達(dá)式由 try!
運(yùn)算符加上緊隨其后的可拋出錯(cuò)誤的表達(dá)式組成,形式如下:
try!
可拋出錯(cuò)誤的表達(dá)式
如果可拋出錯(cuò)誤的表達(dá)式拋出了錯(cuò)誤,將會(huì)引發(fā)運(yùn)行時(shí)錯(cuò)誤。
在二進(jìn)制運(yùn)算符左側(cè)的表達(dá)式被標(biāo)記上 try
、try?
或者 try!
時(shí),這個(gè)運(yùn)算符對(duì)整個(gè)二進(jìn)制表達(dá)式都產(chǎn)生作用。也就是說,你可以使用括號(hào)來明確運(yùn)算符的作用范圍。
sum = try someThrowingFunction() + anotherThrowingFunction() // try 對(duì)兩個(gè)函數(shù)調(diào)用都產(chǎn)生作用
sum = try (someThrowingFunction() + anotherThrowingFunction()) // try 對(duì)兩個(gè)函數(shù)調(diào)用都產(chǎn)生作用
sum = (try someThrowingFunction()) + anotherThrowingFunction() // 錯(cuò)誤:try 只對(duì)第一個(gè)函數(shù)調(diào)用產(chǎn)生作用
try
表達(dá)式不能出現(xiàn)在二進(jìn)制運(yùn)算符的的右側(cè),除非二進(jìn)制運(yùn)算符是賦值運(yùn)算符或者 try
表達(dá)式是被圓括號(hào)括起來的。
關(guān)于 try
、try?
和 try!
的更多信息,以及該如何使用的例子,請參閱 錯(cuò)誤處理。
二元表達(dá)式由中綴運(yùn)算符和左右參數(shù)表達(dá)式組成。形式如下:
左側(cè)參數(shù)
二元運(yùn)算符
右側(cè)參數(shù)
關(guān)于這些運(yùn)算符的更多信息,請參閱 基本運(yùn)算符 和 高級(jí)運(yùn)算符。
關(guān)于 Swift 標(biāo)準(zhǔn)庫提供的運(yùn)算符的更多信息,請參閱 Swift Standard Library Operators Reference。
注意
在解析時(shí),一個(gè)二元表達(dá)式將作為一個(gè)扁平列表表示,然后根據(jù)運(yùn)算符的優(yōu)先級(jí),再進(jìn)一步進(jìn)行組合。例如,2 + 3 * 5
首先被看作具有五個(gè)元素的列表,即2
、+
、3
、*
、5
,隨后根據(jù)運(yùn)算符優(yōu)先級(jí)組合為(2 + (3 * 5))
。
二元表達(dá)式語法
二元表達(dá)式 → 二元運(yùn)算符 前綴表達(dá)式
二元表達(dá)式 → 賦值運(yùn)算符 try運(yùn)算符可選 前綴表達(dá)式
二元表達(dá)式 → 條件運(yùn)算符 try運(yùn)算符可選 前綴表達(dá)式
二元表達(dá)式 → 類型轉(zhuǎn)換運(yùn)算符
二元表達(dá)式列表 → 二元表達(dá)式 二元表達(dá)式列表可選
賦值表達(dá)式會(huì)為某個(gè)給定的表達(dá)式賦值,形式如下;
表達(dá)式
=值
右邊的值會(huì)被賦值給左邊的表達(dá)式。如果左邊表達(dá)式是一個(gè)元組,那么右邊必須是一個(gè)具有同樣元素個(gè)數(shù)的元組。(嵌套元組也是允許的。)右邊的值中的每一部分都會(huì)被賦值給左邊的表達(dá)式中的相應(yīng)部分。例如:
(a, _, (b, c)) = ("test", 9.45, (12, 3))
// a 為 "test",b 為 12,c 為 3,9.45 會(huì)被忽略
賦值運(yùn)算符不返回任何值。
三元條件運(yùn)算符會(huì)根據(jù)條件來對(duì)兩個(gè)給定表達(dá)式中的一個(gè)進(jìn)行求值,形式如下:
條件
?表達(dá)式(條件為真則使用)
:表達(dá)式(條件為假則使用)
如果條件為真,那么對(duì)第一個(gè)表達(dá)式進(jìn)行求值并返回結(jié)果。否則,對(duì)第二個(gè)表達(dá)式進(jìn)行求值并返回結(jié)果。未使用的表達(dá)式不會(huì)進(jìn)行求值。
關(guān)于使用三元條件運(yùn)算符的例子,請參閱 三元條件運(yùn)算符。
三元條件運(yùn)算符語法
三元條件運(yùn)算符 → ? try運(yùn)算符可選 表達(dá)式 :
有 4 種類型轉(zhuǎn)換運(yùn)算符:is
、as
、as?
和as!
。它們有如下的形式:
表達(dá)式
is類型
表達(dá)式
as類型
表達(dá)式
as?類型
表達(dá)式
as!類型
is
運(yùn)算符在運(yùn)行時(shí)檢查表達(dá)式能否向下轉(zhuǎn)化為指定的類型,如果可以則返回 ture
,否則返回 false
。
as
運(yùn)算符在編譯時(shí)執(zhí)行向上轉(zhuǎn)換和橋接。向上轉(zhuǎn)換可將表達(dá)式轉(zhuǎn)換成超類的實(shí)例而無需使用任何中間變量。以下表達(dá)式是等價(jià)的:
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 標(biāo)準(zhǔn)庫中的類型(例如 String
)作為一個(gè)與之相關(guān)的 Foundation 類型(例如 NSString
)來使用,而不需要新建一個(gè)實(shí)例。關(guān)于橋接的更多信息,請參閱 Using Swift with Cocoa and Objective-C (Swift2.2) 中的 Working with Cocoa Data Types。
as?
運(yùn)算符有條件地執(zhí)行類型轉(zhuǎn)換,返回目標(biāo)類型的可選值。在運(yùn)行時(shí),如果轉(zhuǎn)換成功,返回的可選值將包含轉(zhuǎn)換后的值,否則返回 nil
。如果在編譯時(shí)就能確定轉(zhuǎn)換一定會(huì)成功或是失敗,則會(huì)導(dǎo)致編譯報(bào)錯(cuò)。
as!
運(yùn)算符執(zhí)行強(qiáng)制類型轉(zhuǎn)換,返回目標(biāo)類型的非可選值。如果轉(zhuǎn)換失敗,則會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。表達(dá)式 x as! T
效果等同于 (x as? T)!
。
關(guān)于類型轉(zhuǎn)換的更多內(nèi)容和例子,請參閱 類型轉(zhuǎn)換。
類型轉(zhuǎn)換運(yùn)算符語法
類型轉(zhuǎn)換運(yùn)算符 → is 類型
類型轉(zhuǎn)換運(yùn)算符 → as 類型
類型轉(zhuǎn)換運(yùn)算符 → as ? 類型
類型轉(zhuǎn)換運(yùn)算符 → as ! 類型
基本表達(dá)式是最基本的表達(dá)式。它們可以單獨(dú)使用,也可以跟前綴表達(dá)式、二元表達(dá)式、后綴表達(dá)式組合使用。
基本表達(dá)式語法
基本表達(dá)式 → 標(biāo)識(shí)符 泛型實(shí)參子句可選
基本表達(dá)式 → 字面量表達(dá)式
基本表達(dá)式 → self表達(dá)式
基本表達(dá)式 → 超類表達(dá)式
基本表達(dá)式 → 閉包表達(dá)式
基本表達(dá)式 → 圓括號(hào)表達(dá)式
基本表達(dá)式 → 隱式成員表達(dá)式
基本表達(dá)式 → 通配符表達(dá)式
基本表達(dá)式 → 選擇器表達(dá)式
字面量表達(dá)式可由普通字面量(例如字符串或者數(shù)字),字典或者數(shù)組字面量,或者下面列表中的特殊字面量組成:
字面量 | 類型 | 值 |
---|---|---|
#file |
String |
所在的文件名 |
#line |
Int |
所在的行數(shù) |
#column |
Int |
所在的列數(shù) |
#function |
String |
所在的聲明的名字 |
#line
除了上述含義外,還有另一種含義。當(dāng)它出現(xiàn)在單獨(dú)一行時(shí),會(huì)被理解成行控制語句,請參閱線路控制語句。
對(duì)于 #function
,在函數(shù)中會(huì)返回當(dāng)前函數(shù)的名字,在方法中會(huì)返回當(dāng)前方法的名字,在屬性的存取器中會(huì)返回屬性的名字,在特殊的成員如 init
或 subscript
中會(huì)返回這個(gè)關(guān)鍵字的名字,在某個(gè)文件中會(huì)返回當(dāng)前模塊的名字。
#function
作為函數(shù)或者方法的默認(rèn)參數(shù)值時(shí),該字面量的值取決于函數(shù)或方法的調(diào)用環(huán)境。
func logFunctionName(string: String = #function) {
print(string)
}
func myFunction() {
logFunctionName()
}
myFunction() // 打印 “myFunction()”
數(shù)組字面量是值的有序集合,形式如下:
[
值 1
,值 2
,...
]
數(shù)組中的最后一個(gè)表達(dá)式可以緊跟一個(gè)逗號(hào)。數(shù)組字面量的類型是 [T]
,這個(gè) T
就是數(shù)組中元素的類型。如果數(shù)組中包含多種類型,T
則是跟這些類型最近的的公共父類型??諗?shù)組字面量由一組方括號(hào)定義,可用來創(chuàng)建特定類型的空數(shù)組。
var emptyArray: [Double] = []
字典字面量是一個(gè)包含無序鍵值對(duì)的集合,形式如下:
[
鍵 1
:值 1
,鍵 2
:值 2
,...
]
字典中的最后一個(gè)表達(dá)式可以緊跟一個(gè)逗號(hào)。字典字面量的類型是 [Key : Value]
,Key
表示鍵的類型,Value
表示值的類型。如果字典中包含多種類型,那么 Key
表示的類型則為所有鍵最接近的公共父類型,Value
與之相似。一個(gè)空的字典字面量由方括號(hào)中加一個(gè)冒號(hào)組成([:]
),從而與空數(shù)組字面量區(qū)分開,可以使用空字典字面量來創(chuàng)建特定類型的字典。
var emptyDictionary: [String : Double] = [:]
字面量表達(dá)式語法
字面量表達(dá)式 → 字面量
字面量表達(dá)式 → 數(shù)組字面量 | 字典字面量
字面量表達(dá)式 → #file | #line | #column | #function
數(shù)組字面量 → [ 數(shù)組字面量項(xiàng)列表可選 ]
</a> 數(shù)組字面量項(xiàng)列表 → 數(shù)組字面量項(xiàng) ,可選 | 數(shù)組字面量項(xiàng) , 數(shù)組字面量項(xiàng)列表
數(shù)組字面量項(xiàng) → 表達(dá)式
字典字面量 → [ 字典字面量項(xiàng)列表 ] | [ : ]
</a> 字典字面量項(xiàng)列表 → 字典字面量項(xiàng) ,可選 | 字典字面量項(xiàng) , 字典字面量項(xiàng)列表
字典字面量項(xiàng) → 表達(dá)式 : 表達(dá)式
self
表達(dá)式是對(duì)當(dāng)前類型或者當(dāng)前實(shí)例的顯式引用,它有如下形式:
self
self.成員名稱
self[下標(biāo)索引
]
self(構(gòu)造器參數(shù)
)
self.init(構(gòu)造器參數(shù)
)
如果在構(gòu)造器、下標(biāo)、實(shí)例方法中,self
引用的是當(dāng)前類型的實(shí)例。在一個(gè)類型方法中,self
引用的是當(dāng)前的類型。
當(dāng)訪問成員時(shí),self
可用來區(qū)分重名變量,例如函數(shù)的參數(shù):
class SomeClass {
var greeting: String
init(greeting: String) {
self.greeting = greeting
}
}
在 mutating
方法中,你可以對(duì) 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 表達(dá)式語法
self 表達(dá)式 → self | self 方法表達(dá)式 | self 下標(biāo)表達(dá)式 | self 構(gòu)造器表達(dá)式</a> self 方法表達(dá)式 → self . 標(biāo)識(shí)符
self 下標(biāo)表達(dá)式 → self [ 表達(dá)式 ] self 構(gòu)造器表達(dá)式 → self . init
超類表達(dá)式可以使我們在某個(gè)類中訪問它的超類,它有如下形式:
super.
成員名稱
super[下標(biāo)索引
]
super.init(構(gòu)造器參數(shù)
)
第一種形式用來訪問超類的某個(gè)成員,第二種形式用來訪問超類的下標(biāo),第三種形式用來訪問超類的構(gòu)造器。
子類可以通過超類表達(dá)式在它們的成員、下標(biāo)和構(gòu)造器中使用超類中的實(shí)現(xiàn)。
超類表達(dá)式語法
</a> 超類表達(dá)式 → 超類方法表達(dá)式 | 超類下標(biāo)表達(dá)式 | 超類構(gòu)造器表達(dá)式
超類方法表達(dá)式 → super . 標(biāo)識(shí)符
</a> 超類下標(biāo)表達(dá)式 → super [ 表達(dá)式 ]
超類構(gòu)造器表達(dá)式 → super . init
閉包表達(dá)式會(huì)創(chuàng)建一個(gè)閉包,在其他語言中也叫 lambda 或匿名函數(shù)。跟函數(shù)一樣,閉包包含了待執(zhí)行的代碼,不同的是閉包還會(huì)捕獲所在環(huán)境中的常量和變量。它的形式如下:
{ (parameters) -> return type in
statements
}
閉包的參數(shù)聲明形式跟函數(shù)一樣,請參閱 函數(shù)聲明。
閉包還有幾種特殊的形式,能讓閉包使用起來更加簡潔:
in
關(guān)鍵字。如果被省略的類型無法被編譯器推斷,那么就會(huì)導(dǎo)致編譯錯(cuò)誤。$
加上其索引位置,例如 $0
、$1
、$2
分別表示第一個(gè)、第二個(gè)、第三個(gè)參數(shù),以此類推。下面幾個(gè)閉包表達(dá)式是等價(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)用表達(dá)式。
默認(rèn)情況下,閉包會(huì)捕獲附近作用域中的常量和變量,并使用強(qiáng)引用指向它們。你可以通過一個(gè)捕獲列表來顯式指定它的捕獲行為。
捕獲列表在參數(shù)列表之前,由中括號(hào)括起來,里面是由逗號(hào)分隔的一系列表達(dá)式。一旦使用了捕獲列表,就必須使用 in
關(guān)鍵字,即使省略了參數(shù)名、參數(shù)類型和返回類型。
捕獲列表中的項(xiàng)會(huì)在閉包創(chuàng)建時(shí)被初始化。每一項(xiàng)都會(huì)用閉包附近作用域中的同名常量或者變量的值初始化。例如下面的代碼示例中,捕獲列表包含 a
而不包含 b
,這將導(dǎo)致這兩個(gè)變量具有不同的行為。
var a = 0
var b = 0
let closure = { [a] in
print(a, b)
}
a = 10
b = 10
closure()
// 打印 “0 10”
在示例中,變量 b
只有一個(gè),然而,變量 a
有兩個(gè),一個(gè)在閉包外,一個(gè)在閉包內(nèi)。閉包內(nèi)的變量 a
會(huì)在閉包創(chuàng)建時(shí)用閉包外的變量 a
的值來初始化,除此之外它們并無其他聯(lián)系。這意味著在閉包創(chuàng)建后,改變某個(gè) a
的值都不會(huì)對(duì)另一個(gè) a
的值造成任何影響。與此相反,閉包內(nèi)外都是同一個(gè)變量 b
,因此在閉包外改變其值,閉包內(nèi)的值也會(huì)受影響。
如果閉包捕獲的值具有引用語義則有所不同。例如,下面示例中,有兩個(gè)變量 x
,一個(gè)在閉包外,一個(gè)在閉包內(nèi),由于它們的值是引用語義,雖然這是兩個(gè)不同的變量,它們卻都引用著同一實(shí)例。
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
來修飾它,閉包會(huì)分別用弱引用和無主引用來捕獲該值。
myFunction { print(self.title) } // 以強(qiáng)引用捕獲
myFunction { [weak self] in print(self!.title) } // 以弱引用捕獲
myFunction { [unowned self] in print(self.title) } // 以無主引用捕獲
在捕獲列表中,也可以將任意表達(dá)式的值綁定到一個(gè)常量上。該表達(dá)式會(huì)在閉包被創(chuàng)建時(shí)進(jìn)行求值,閉包會(huì)按照指定的引用類型來捕獲表達(dá)式的值。例如:
// 以弱引用捕獲 self.parent 并賦值給 parent
myFunction { [weak parent = self.parent] in print(parent!.title) }
關(guān)于閉包表達(dá)式的更多信息和例子,請參閱 閉包表達(dá)式。關(guān)于捕獲列表的更多信息和例子,請參閱 解決閉包引起的循環(huán)強(qiáng)引用。
閉包表達(dá)式語法
閉包簽名 → 參數(shù)子句 函數(shù)結(jié)果可選 in
閉包簽名 → 標(biāo)識(shí)符列表 函數(shù)結(jié)果可選 in
閉包簽名 → 捕獲列表 參數(shù)子句 函數(shù)結(jié)果可選 in
閉包簽名 → 捕獲列表 標(biāo)識(shí)符列表 函數(shù)結(jié)果可選 in
閉包簽名 → 捕獲列表 in
捕獲列表 → [ 捕獲列表項(xiàng)列表 ]
</a> 捕獲列表項(xiàng)列表 → 捕獲列表項(xiàng) | 捕獲列表項(xiàng) , 捕獲列表項(xiàng)列表
捕獲列表項(xiàng) → 捕獲說明符可選 表達(dá)式
捕獲說明符 → weak | unowned | unowned(safe) | unowned(unsafe)
若類型可被推斷出來,可以使用隱式成員表達(dá)式來訪問某個(gè)類型的成員(例如某個(gè)枚舉成員或某個(gè)類型方法),形式如下:
.
成員名稱
例如:
var x = MyEnumeration.SomeValue
x = .AnotherValue
隱式成員表達(dá)式語法
隱式成員表達(dá)式 → . 標(biāo)識(shí)符
圓括號(hào)表達(dá)式由圓括號(hào)和其中多個(gè)逗號(hào)分隔的子表達(dá)式組成。每個(gè)子表達(dá)式前面可以有一個(gè)標(biāo)識(shí)符,用冒號(hào)隔開。圓括號(hào)表達(dá)式形式如下:
(
標(biāo)識(shí)符 1
:表達(dá)式 1
,標(biāo)識(shí)符 2
:表達(dá)式 2
,...
)
使用圓括號(hào)表達(dá)式來創(chuàng)建元組,然后將其作為參數(shù)傳遞給函數(shù)。如果某個(gè)圓括號(hào)表達(dá)式中只有一個(gè)子表達(dá)式,那么它的類型就是子表達(dá)式的類型。例如,表達(dá)式 (1)
的類型是 Int
,而不是 (Int)
。
圓括號(hào)表達(dá)式語法
</a> 圓括號(hào)表達(dá)式 → ( 表達(dá)式元素列表可選 )
表達(dá)式元素列表 → 表達(dá)式元素 | 表達(dá)式元素 , 表達(dá)式元素列表
表達(dá)式元素 → 表達(dá)式 | 標(biāo)識(shí)符 : 表達(dá)式
通配符表達(dá)式可以在賦值過程中顯式忽略某個(gè)值。例如下面的代碼中,10
被賦值給 x
,而 20
則被忽略:
(x, _) = (10, 20)
// x 為 10,20 被忽略
選擇器表達(dá)式可以讓你通過選擇器來引用在Objective-C中方法(method)和屬性(property)的setter和getter方法。
#selector(方法名) #selector(getter: 屬性名) #selector(setter: 屬性名)
方法名和屬性名必須是存在于 Objective-C 運(yùn)行時(shí)中的方法和屬性的引用。選擇器表達(dá)式的返回值是一個(gè) Selector 類型的實(shí)例。例如:
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)
當(dāng)為屬性的getter創(chuàng)建選擇器時(shí),屬性名可以是變量屬性或者常量屬性的引用。但是當(dāng)為屬性的setter創(chuàng)建選擇器時(shí),屬性名只可以是對(duì)變量屬性的引用。
方法名稱可以包含圓括號(hào)來進(jìn)行分組,并使用as 操作符來區(qū)分具有相同方法名但類型不同的方法, 例如:
extension SomeClass {
@objc(doSomethingWithString:)
func doSomething(_ x: String) { }
}
let anotherSelector = #selector(SomeClass.doSomething(_:) as (SomeClass) -> (String) -> Void)
由于選擇器是在編譯時(shí)創(chuàng)建的,因此編譯器可以檢查方法或者屬性是否存在,以及是否在運(yùn)行時(shí)暴露給了 Objective-C 。
注意
雖然方法名或者屬性名是個(gè)表達(dá)式,但是它不會(huì)被求值。
更多關(guān)于如何在 Swift 代碼中使用選擇器來與 Objective-C API 進(jìn)行交互的信息,請參閱 Using Swift with Cocoa and Objective-C (Swift 3) 中Objective-C Selectors部分。
選擇器表達(dá)式語法
選擇器表達(dá)式 → #selector ( 表達(dá)式 )
選擇器表達(dá)式 → #selector ( getter:表達(dá)式 )
選擇器表達(dá)式 → #selector ( setter:表達(dá)式 )
后綴表達(dá)式就是在某個(gè)表達(dá)式的后面運(yùn)用后綴運(yùn)算符或其他后綴語法。從語法構(gòu)成上來看,基本表達(dá)式也是后綴表達(dá)式。
關(guān)于這些運(yùn)算符的更多信息,請參閱 基本運(yùn)算符 和 高級(jí)運(yùn)算符。
關(guān)于 Swift 標(biāo)準(zhǔn)庫提供的運(yùn)算符的更多信息,請參閱 Swift Standard Library Operators Reference。
后綴表達(dá)式語法
后綴表達(dá)式 → 基本表達(dá)式
后綴表達(dá)式 → 后綴表達(dá)式 后綴運(yùn)算符
后綴表達(dá)式 → 函數(shù)調(diào)用表達(dá)式
后綴表達(dá)式 → 構(gòu)造器表達(dá)式
后綴表達(dá)式 → 顯式成員表達(dá)式
后綴表達(dá)式 → 后綴 self 表達(dá)式
后綴表達(dá)式 → dynamicType 表達(dá)式
后綴表達(dá)式 → 下標(biāo)表達(dá)式
后綴表達(dá)式 → 強(qiáng)制取值表達(dá)式
后綴表達(dá)式 → 可選鏈表達(dá)式
函數(shù)調(diào)用表達(dá)式由函數(shù)名和參數(shù)列表組成,形式如下:
函數(shù)名
(參數(shù) 1
,參數(shù) 2
)
函數(shù)名可以是值為函數(shù)類型的任意表達(dá)式。
如果函數(shù)聲明中指定了參數(shù)的名字,那么在調(diào)用的時(shí)候也必須得寫出來。這種函數(shù)調(diào)用表達(dá)式具有以下形式:
函數(shù)名
(參數(shù)名 1
:參數(shù) 1
,參數(shù)名 2
:參數(shù) 2
)
如果函數(shù)的最后一個(gè)參數(shù)是函數(shù)類型,可以在函數(shù)調(diào)用表達(dá)式的尾部(右圓括號(hào)之后)加上一個(gè)閉包,該閉包會(huì)作為函數(shù)的最后一個(gè)參數(shù)。如下兩種寫法是等價(jià)的:
// someFunction 接受整數(shù)和閉包參數(shù)
someFunction(x, f: {$0 == 13})
someFunction(x) {$0 == 13}
如果閉包是該函數(shù)的唯一參數(shù),那么圓括號(hào)可以省略。
// someFunction 只接受一個(gè)閉包參數(shù)
myData.someMethod() {$0 == 13}
myData.someMethod {$0 == 13}
函數(shù)調(diào)用表達(dá)式語法
</a> 函數(shù)調(diào)用表達(dá)式 → 后綴表達(dá)式 圓括號(hào)表達(dá)式
函數(shù)調(diào)用表達(dá)式 → 后綴表達(dá)式 圓括號(hào)表達(dá)式可選 尾隨閉包
尾隨閉包 → 閉包表達(dá)式
構(gòu)造器表達(dá)式用于訪問某個(gè)類型的構(gòu)造器,形式如下:
表達(dá)式
.init(構(gòu)造器參數(shù)
)
你可以在函數(shù)調(diào)用表達(dá)式中使用構(gòu)造器表達(dá)式來初始化某個(gè)類型的新實(shí)例。也可以使用構(gòu)造器表達(dá)式來代理給超類構(gòu)造器。
class SomeSubClass: SomeSuperClass {
override init() {
// 此處為子類構(gòu)造過程
super.init()
}
}
和函數(shù)類似,構(gòu)造器表達(dá)式可以作為一個(gè)值。 例如:
// 類型注解是必須的,因?yàn)?String 類型有多種構(gòu)造器
let initializer: Int -> String = String.init
let oneTwoThree = [1, 2, 3].map(initializer).reduce("", combine: +)
print(oneTwoThree)
// 打印 “123”
如果通過名字來指定某個(gè)類型,可以不用構(gòu)造器表達(dá)式而直接使用類型的構(gòu)造器。在其他情況下,你必須使用構(gòu)造器表達(dá)式。
let s1 = SomeType.init(data: 3) // 有效
let s2 = SomeType(data: 1) // 有效
let s4 = someValue.dynamicType(data: 5) // 錯(cuò)誤
let s3 = someValue.dynamicType.init(data: 7) // 有效
構(gòu)造器表達(dá)式語法
構(gòu)造器表達(dá)式 → 后綴表達(dá)式 . init
構(gòu)造器表達(dá)式 → 后綴表達(dá)式 . init ( 參數(shù)名稱 )
顯式成員表達(dá)式允許我們訪問命名類型、元組或者模塊的成員,其形式如下:
表達(dá)式
.成員名
命名類型的某個(gè)成員在原始實(shí)現(xiàn)或者擴(kuò)展中定義,例如:
class SomeClass {
var someProperty = 42
}
let c = SomeClass()
let y = c.someProperty // 訪問成員
元組的成員會(huì)隱式地根據(jù)表示它們出現(xiàn)順序的整數(shù)來命名,以 0 開始,例如:
var t = (10, 20, 30)
t.0 = t.1
// 現(xiàn)在元組 t 為 (20, 20, 30)
對(duì)于模塊的成員來說,只能直接訪問頂級(jí)聲明中的成員。
為了區(qū)分只有參數(shù)名有所不同的方法或構(gòu)造器,在圓括號(hào)中寫出參數(shù)名,參數(shù)名后緊跟一個(gè)冒號(hào),對(duì)于沒有參數(shù)名的參數(shù),使用下劃線代替參數(shù)名。而對(duì)于重載方法,則需使用類型標(biāo)注進(jìn)行區(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:) // 無歧義
如果點(diǎn)號(hào)(.
)出現(xiàn)在行首,它會(huì)被視為顯式成員表達(dá)式的一部分,而不是隱式成員表達(dá)式的一部分。例如如下代碼所展示的被分為多行的鏈?zhǔn)椒椒ㄕ{(diào)用:
let x = [10, 3, 20, 15, 4]
.sort()
.filter { $0 > 5 }
.map { $0 * 100 }
顯式成員表達(dá)式語法
顯式成員表達(dá)式 → 后綴表達(dá)式 . 十進(jìn)制數(shù)字
顯式成員表達(dá)式 → 后綴表達(dá)式 . 標(biāo)識(shí)符 泛型實(shí)參子句可選
顯式成員表達(dá)式 → 后綴表達(dá)式 . 標(biāo)識(shí)符 ( 參數(shù)名稱 )</a> 參數(shù)名稱 → 參數(shù)名 參數(shù)名稱可選
參數(shù)名 → 標(biāo)識(shí)符 :
后綴 self
表達(dá)式由某個(gè)表達(dá)式或類型名緊跟 .self
組成,其形式如下:
表達(dá)式
.self類型
.self
第一種形式返回表達(dá)式的值。例如:x.self
返回 x
。
第二種形式返回相應(yīng)的類型。我們可以用它來獲取某個(gè)實(shí)例的類型作為一個(gè)值來使用。例如,SomeClass.self
會(huì)返回 SomeClass
類型本身,你可以將其傳遞給相應(yīng)函數(shù)或者方法作為參數(shù)。
后綴 self 表達(dá)式語法
后綴 self 表達(dá)式 → 后綴表達(dá)式 . self
dynamicType 表達(dá)式由類似函數(shù)調(diào)用表達(dá)式(Function Call Expression)的特殊語法表達(dá)式組成,形式如下:
type(of:
表達(dá)式
)
上述形式中的表達(dá)式不能是類型名。type(of:) 表達(dá)式會(huì)返回某個(gè)實(shí)例在運(yùn)行時(shí)的類型,具體請看下面的例子:
class SomeBaseClass {
class func printClassName() {
print("SomeBaseClass")
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
print("SomeSubClass")
}
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在編譯時(shí)的靜態(tài)類型為 SomeBaseClass,
// 在運(yùn)行時(shí)的動(dòng)態(tài)類型為 SomeSubClass
type(of: someInstance).printClassName()
// 打印 “SomeSubClass”
動(dòng)態(tài)類型表達(dá)式語法
動(dòng)態(tài)類型表達(dá)式 → type(of:表達(dá)式) . dynamicType
可通過下標(biāo)表達(dá)式訪問相應(yīng)的下標(biāo),形式如下:
表達(dá)式
[索引表達(dá)式
]
要獲取下標(biāo)表達(dá)式的值,可將索引表達(dá)式作為下標(biāo)表達(dá)式的參數(shù)來調(diào)用下標(biāo) getter。下標(biāo) setter 的調(diào)用方式與之一樣。
關(guān)于下標(biāo)的聲明,請參閱 協(xié)議下標(biāo)聲明。
當(dāng)你確定可選值不是 nil
時(shí),可以使用強(qiáng)制取值表達(dá)式來強(qiáng)制解包,形式如下:
表達(dá)式
!
如果該表達(dá)式的值不是 nil
,則返回解包后的值。否則,拋出運(yùn)行時(shí)錯(cuò)誤。
返回的值可以被修改,無論是修改值本身,還是修改值的成員。例如:
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]]
強(qiáng)制取值語法
強(qiáng)制取值表達(dá)式 → 后綴表達(dá)式 !
可選鏈表達(dá)式提供了一種使用可選值的便捷方法,形式如下:
表達(dá)式
?
后綴 ?
運(yùn)算符會(huì)根據(jù)表達(dá)式生成可選鏈表達(dá)式而不會(huì)改變表達(dá)式的值。
如果某個(gè)后綴表達(dá)式包含可選鏈表達(dá)式,那么它的執(zhí)行過程會(huì)比較特殊。如果該可選鏈表達(dá)式的值是 nil
,整個(gè)后綴表達(dá)式會(huì)直接返回 nil
。如果該可選鏈表達(dá)式的值不是 nil
,則返回可選鏈表達(dá)式解包后的值,并將該值用于后綴表達(dá)式中剩余的表達(dá)式。在這兩種情況下,整個(gè)后綴表達(dá)式的值都會(huì)是可選類型。
如果某個(gè)后綴表達(dá)式中包含了可選鏈表達(dá)式,那么只有最外層的表達(dá)式會(huì)返回一個(gè)可選類型。例如,在下面的例子中,如果 c
不是 nil
,那么它的值會(huì)被解包,然后通過 .property
訪問它的屬性,接著進(jìn)一步通過 .performAction()
調(diào)用相應(yīng)方法。整個(gè) c?.property.performAction()
表達(dá)式返回一個(gè)可選類型的值,而不是多重可選類型。
var c: SomeClass?
var result: Bool? = c?.property.performAction()
上面的例子跟下面的不使用可選鏈表達(dá)式的例子等價(jià):
var result: Bool? = nil
if let unwrappedC = c {
result = unwrappedC.property.performAction()
}
可選鏈表達(dá)式解包后的值可以被修改,無論是修改值本身,還是修改值的成員。如果可選鏈表達(dá)式的值為 nil
,則表達(dá)式右側(cè)的賦值操作不會(huì)被執(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 不會(huì)被執(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]]
可選鏈表達(dá)式語法
可選鏈表達(dá)式 → 后綴表達(dá)式 ?