swift4新功能
內(nèi)容
開區(qū)間
字符
同 件內(nèi)的擴(kuò)展,私有聲明可
智能Key path
編碼和解碼
協(xié)議相關(guān)類型的約束字典(Dictionary)和集合(Set)的增強(qiáng)MutableCollection.swapAt法reduce和inout
泛型下標(biāo)
NSNumber橋接
類和協(xié)議的組合
開區(qū)間
SE-0172帶來 種新的RangeExpression協(xié)議和 組前綴/后綴操作符給開區(qū)間.比如現(xiàn)在區(qū)間
論是上界還是下界都可以不指定.
限序
你可以 開區(qū)間來造 個(gè) 限序,對 期使enumerated()法的同學(xué)來說,這是 個(gè)福,尤
其是當(dāng)你不想序號從0開始的時(shí)候:
let字 表= ["a","b","c","d"]
let加序號的字 表= zip(1...,字 表)
Array(加序號的字 表)集合的下標(biāo)
在集合的下標(biāo)中 開區(qū)間的話,集合的startIndex or endIndex會(huì)“智能填充”缺失的那 邊.
let numbers = [1,2,3,4,5,6,7,8,9,10]
numbers[5...]取代numbers[5..
開區(qū)間可 于 式匹配,比如 個(gè)switch語 中case表達(dá)式.不過,編譯器好像還不能(暫時(shí)?)判
定switch已被窮盡.
let value = 5
switch value {
case 1...:
print("于0")
case 0:
print("0")
case ..<0:
print("于0")
default:
fatalError("不可到達(dá)")
}
字符
多 字符 字
SE-0168帶來 種簡潔定義多 字符 的語法,使(""").在 個(gè)多 字符? 并不需要寫轉(zhuǎn)義字
符,也就是說 多數(shù) 本格式(如JSON或HTML)就可以直接粘貼? 須任何轉(zhuǎn)義.結(jié)尾三引號的
縮進(jìn),決定 每? 頭部被裁剪的空格多少. Python:致敬我嗎Kotlin:我也早有這功能
let多 字符= """
這是 個(gè)多 字符.不需要在這 轉(zhuǎn)義"引號".結(jié)尾三引號的位置,控制空格的裁剪數(shù).
"""
print(多 字符)
可以打開控制臺(菜單View > Debug Area > Activate Console)來看print的輸出.
字符"雙"變回 個(gè)Collection,沒錯(cuò),天地暫停,時(shí)光倒流
SE-0163是Swift 4字符 模型的第 部分修正.最 變化String再度是 個(gè)Collection (因?yàn)樵赟wift 1.x中是這樣的),比如String.CharacterView已經(jīng)被并入其 類型中. (其他view,
UnicodeScalarView, UTF8View,和UTF16View,依舊存在.)
注意SE-0163還沒完全實(shí)現(xiàn)并且這條建議中還有很多字符 相關(guān)的提議(意思是還有的折騰).
let歡迎語= "儂好Bobo, !"不需要再鉆到.characters屬性? 去
歡迎語.count
for字in歡迎語{
print(字)
}
Substring是字符 切片后的新類型
字符 切片現(xiàn)在是Substring類型的實(shí). String和Substring兩者都遵從StringProtocol.乎所
有字符API都在StringProtocol所以String和Substring為很 程度是 樣的.
let逗號的位置=歡迎語.index(of: ",")!
let substring =歡迎語[..<逗號的位置]
type(of: substring)
Substring可以調(diào)String的API
print(substring.uppercased())
Unicode 9
Swift 4即將 持Unicode 9,當(dāng)前正在修正? 些時(shí)髦emoji適當(dāng)?shù)恼Z義問題.下 的所有字符計(jì)數(shù)
是1,和實(shí)際的對比:
"".count+膚"".count有4個(gè)成員的家庭
"\u{200D}\u{200D}\u{200D}".count家庭+膚"".count+膚+職業(yè)Character.unicodeScalars屬性
現(xiàn)在可以直接訪問 個(gè)Character的unicode編碼值,不 先轉(zhuǎn)成String (SE-0178):
let c: Character = ""
Array(c.unicodeScalars)同 件內(nèi)的擴(kuò)展,私有聲明可
SE-0169改 訪問控制規(guī)則,比如在同 件內(nèi)的擴(kuò)展中,原類型的private聲明也是可 的.這種改
進(jìn)可讓同 件內(nèi)保持使private分割類型定義成為可能,減少不受歡迎的fileprivate關(guān)鍵詞的使.
struct SortedArray {
private var storage: [Element] = []init(unsorted: [Element]) {
storage = unsorted.sorted()
}
}
extension SortedArray {
mutating func insert(_ element: Element) {
storage此處可storage.append(element)
storage.sort()
}
}
let array = SortedArray(unsorted: [3,1,2])
storage此處不可(不像fileprivate)
array.storage error: 'storage' is inaccessible due to 'private' protection level智能key path
SE-0161描述的新式key path有可能搞 個(gè)Swift 4的 新聞.不像Cocoa中基于字符 的那樣too
simple, Swift中的可是強(qiáng)類型的,你們要認(rèn)真學(xué)習(xí).
struct{
var名字: String
}
struct書{
var標(biāo)題: String
var作者: []
var第 作者:{
return作者.first!
}
}
let Vergil =(名字: "Vergil")
let Xernaga =(名字: "Xernaga")
let Kotlin快速入 書=書(標(biāo)題: "Kotlin快速入",作者: [Vergil, Xernaga])
Key path由 個(gè)根類型開始,和其下任意深度的屬性鏈和下標(biāo)名組成.
你可以寫 個(gè)key path由 個(gè)反斜杠開始: \書.標(biāo)題.每個(gè)類型 動(dòng)獲取 個(gè)[keyPath: ...]下標(biāo)可
以設(shè)置或獲取指定key path的值.
Kotlin快速入 書[keyPath: \書.標(biāo)題]
Key path可深入并 持計(jì)算屬性
Kotlin快速入 書[keyPath: \書.第 作者.名字]
Key path是可被存儲(chǔ)和操作的對象.比如,你可以給 個(gè)key path加上額外字段深入到作者.
let作者KeyPath = \書.第 作者
type(of:作者KeyPath)
let名字KeyPath =作者KeyPath.appending(path: \.名字)可以省 類型名,如果編譯器能推斷的話
Kotlin快速入 書[keyPath:名字KeyPath]
下標(biāo)Key path
Key paths也 持下標(biāo).如此 來可以非常 捷的深入到數(shù)組或字典這些集合類型中.不過這功能
在當(dāng)前snapshot還未實(shí)現(xiàn).
壓縮化 和 序 化
SE-0166: Swift Archival & Serialization定義? 種為任意Swift類型(class, struct,和enum)來描
述? 如何壓縮和序 化的 法.類型可遵從Codable協(xié)議讓? 可(解)壓縮.多數(shù)情況下添加Codable協(xié)議就可以讓你的 定義類型完美解壓縮,因?yàn)榫幾g器可以 成 個(gè)
默認(rèn)的實(shí)現(xiàn),前提是所有成員類型都是Codable的.當(dāng)然你可以覆蓋默認(rèn) 法如果需要優(yōu)化 定義
類型的編碼.這個(gè)說來話—還請研讀SE-0166.
遵從Codable協(xié)議,讓 個(gè) 定義類型(和其所有成員)可壓縮struct撲克: Codable {
enum全部花: String, Codable {
case桃,花,紅,片
}
enum全部點(diǎn)數(shù): Int, Codable {
case尖= 1,,三,四,五,六,七,八,九,,鉤,蛋,老K
}
var花:全部花
var點(diǎn)數(shù):全部點(diǎn)數(shù)}
let我的牌= [撲克(花: .桃,點(diǎn)數(shù): .尖),撲克(花: .紅,點(diǎn)數(shù): .蛋)]編碼
旦有 個(gè)Codable值,你要把它傳遞給 個(gè)編碼器以 壓縮.
Codable協(xié)議的基礎(chǔ)設(shè)施可以寫? 的編解碼器,不過Swift同時(shí)為JSON提供 個(gè)內(nèi)置的編解
碼器(JSONEncoder和JSONDecoder)和屬性 表(PropertyListEncoder和PropertyListDecoder).這些是在SE-0167中定義的. NSKeyedArchiver同樣 持所有的Codable類型.
import Foundation
var encoder = JSONEncoder()
JSONEncoder提供的可定制化屬性encoder.dataEncodingStrategy
encoder.dateEncodingStrategy
encoder.nonConformingFloatEncodingStrategy
encoder.outputFormatting = .prettyPrinted格式化的json字符encoder.userInfo
let jsonData = try encoder.encode(我的牌)
String(data: jsonData, encoding: .utf8)
解碼
let decoder = JSONDecoder()
let decoded = try decoder.decode([撲克].self, from: jsonData)協(xié)議相關(guān)類型的約束
SE-0142:協(xié)議的相關(guān)類型可以where語 約束.看似? 步,卻是類型系統(tǒng)表達(dá)能 的? 步,讓
標(biāo)準(zhǔn)庫可以 幅簡化.喜 普奔的是, Sequence和Collection在Swift 4中 上這個(gè)就 直觀.
Sequence.Element
Sequence現(xiàn)在有? 的相關(guān)類型Element .原先Swift 3中到處露臉的Iterator.Element ,現(xiàn)在
瘦 成Element:
extension Sequence where Element: Numeric {
var求和: Element {
var結(jié)果: Element = 0
for單個(gè)元素in self {結(jié)果+=單個(gè)元素
}
return結(jié)果}
}
[1,2,3,4].求和
當(dāng)擴(kuò)展Sequence和Collection時(shí)所需約束 少
在Swift 3時(shí)代,這種擴(kuò)展需要很多的約束:
extension Collection where Iterator.Element: Equatable,
SubSequence: Sequence,
SubSequence.Iterator.Element == Iterator.Element
在Swift 4,編譯器已經(jīng)提前知道 上述3個(gè)約束中的2個(gè),因?yàn)榭梢?相關(guān)類型的where語 來表
達(dá)它們.
extension Collection where Element: Equatable {
func頭尾鏡像(_ n: Int) Bool {
let頭= prefix(n)
let尾= suffix(n).reversed()
return頭.elementsEqual(尾)
}
}
[1,2,3,4,2,1].頭尾鏡像(2)
字典(Dictionary)和 集合(Set)的增強(qiáng)
SE-0165加? 些很奶死的Dictionary和Set增強(qiáng).基于序(Sequence)的構(gòu)造器
從 個(gè)鍵值對序 構(gòu)造字典.
let熱 編程語= ["Swift", "Python", "Kotlin"]
let熱 編程語 排= Dictionary(uniqueKeysWithValues: zip(1...,熱 編程語))熱 編程語 排[2]
合并(merge)構(gòu)造器& merge法
當(dāng)從 個(gè)序 構(gòu)造字典,或把 個(gè)序 合并到字典中,描述如何處 重復(fù)的鍵.
let熱 技術(shù)= [("蘋果", "Swift"), ("歌", "TensorFlow"), ("蘋果", "Swift Playgrouds"),
("蘋果", "ARKit"), ("歌", "TensorFlowLite"),("歌", "Kotlin"),("蘋果", "Core ML")]
let商= Dictionary(熱 技術(shù), uniquingKeysWith: { (第,最后) in最后})
商
合并構(gòu)造器或merge法遇到 個(gè)字典時(shí)就沒那么舒服.因?yàn)樽值涞脑仡愋褪?個(gè) 帶標(biāo)簽的
元組型(key: Key, value: Value)但上述2個(gè) 法卻要求 個(gè)? 標(biāo)簽的 元組型(Key, Value),不得已
要? 轉(zhuǎn)換.希望這個(gè)今后能完善.SR-922和SR-4969.
let默認(rèn)設(shè)置= ["動(dòng)登錄": false, "已綁定 機(jī)": false, "藍(lán)牙開啟": false]
var戶設(shè)置= ["動(dòng)登錄": true, "已綁定 機(jī)": false]
會(huì)產(chǎn)? 個(gè)煩 的類型轉(zhuǎn)換警告
let合并的設(shè)置=戶設(shè)置.merge(默認(rèn)設(shè)置) { (old, _) in old }
只能使 以下替代:
戶設(shè)置.merge(默認(rèn)設(shè)置.map { $0 }) { (old, _) in old }戶設(shè)置
下標(biāo)的默認(rèn)值
你現(xiàn)在可以給下標(biāo)中加 個(gè)默認(rèn)值參數(shù),當(dāng)key不存在時(shí)會(huì)返回這個(gè)值,這樣 可讓返回類型非Optional.
熱 編程語 排[4, default: "(未知)"]
/*:在你想通過下標(biāo) 新 個(gè)值時(shí),這個(gè)功能就非常有:
*/
import Foundation
var詞組= """
天姥連天向天橫 勢拔五岳掩 城
天臺四萬八千丈 對此欲倒東南傾
我欲因之夢吳越? 夜 度鏡湖
湖 照我影 送我 剡溪
"""
var出現(xiàn)頻率: [Character: Int] = [:]
for詞in詞組.components(separatedBy: .whitespacesAndNewlines).joined() {
出現(xiàn)頻率[詞, default: 0] += 1
}
for (詞,次數(shù)) in出現(xiàn)頻率{
if次數(shù)> 1 {
print(詞,次數(shù))
}
}
Dictionary相關(guān)的map和filter
filter返回 個(gè)Dictionary非Array.相似的,新 法mapValues轉(zhuǎn)換值的同時(shí)保持字典結(jié)構(gòu).
let filtered =熱 編程語 排.filter {
$0.key % 2 == 0
}
type(of: filtered)
let mapped =熱 編程語 排.mapValues { value in
value.uppercased()
}
mapped
Set.filter現(xiàn)在同樣返回 個(gè)Set不是Array.
let set: Set = [1,2,3,4,5]
let filteredSet = set.filter { $0 % 2 == 0 }type(of: filteredSet)
分組 個(gè)序
把 個(gè)序 分成 組,比如聯(lián)系 按姓分組.
let聯(lián)系= ["張三豐", "李思思", "張素芳", "李", "王", "張 軍"]
let通訊錄= Dictionary(grouping:聯(lián)系, by: { $0.first! })
通訊錄
SE-0173介紹? 種交換 個(gè)集合中兩個(gè)元素的新 法.與既有的swap(::)法不同, swapAt(::)接受 個(gè)要交換的元素切片,不是整個(gè)元素本(通過inout參數(shù)).
加這個(gè)的 的是swap法帶2個(gè)inout參數(shù) 不再兼容新的獨(dú)占式內(nèi)存訪問規(guī)則,SE-0176.既有
的swap(::)法不能再交換同 個(gè)集合中的兩個(gè)元素.
var numbers = [1,2,3,4,5]
numbers.swapAt(0,1)
Swift 4中非法swap(&numbers[3], &numbers[4])numbers
reduce和inout
SE-0171新增reduce的 個(gè)變體,讓部分結(jié)果以inout傳遞給組合函數(shù).如此 來可以通過消除
中間結(jié)果的副本來遞增 個(gè)序,幅提升reduce算法的性能.
SE-0171為實(shí)現(xiàn).
尚未實(shí)現(xiàn)
extension Sequence where Element: Equatable {
func uniq() [Element] {
return reduce(into: []) { (result: inout [Element], element) in
if result.last != element {
result.append(element)
}
}
}
}
[1,1,1,2,3,3,4].uniq()
泛型下標(biāo)
托SE-0148的福,下標(biāo)現(xiàn)在可以有泛型參數(shù)和返回類型.
最權(quán)威的? 莫過于表JSON數(shù)據(jù):你可以定義 個(gè)泛型下標(biāo)來保持調(diào) 者期望類型的內(nèi)容.
struct JSON {
fileprivate var storage: [String:Any]
init(dictionary: [String:Any]) {
self.storage = dictionary
}
subscript(key: String) T? {
return storage[key] as? T
}
}
let json = JSON(dictionary: [
"城市名": "北京",
"國家代碼": "cn",
"": 21_710_000
])
沒必要as? Int
let population: Int? = json[""]
另 個(gè): Collection的 個(gè)下標(biāo)接受 個(gè)泛型索引序,并返回 個(gè)這些索引所在的數(shù)組:
extension Collection {
subscript(indices: Indices) [Element] where Indices.Element == Index {
var result: [Element] = []
for index in indices {
result.append(self[index])
}
return result
}
}
let words = "我 思 故 我 在".split(separator: " ")words[[1,2]]
NSNumber橋接
SE-0170修正部分危險(xiǎn) 為當(dāng)橋接Swift原 數(shù)字類型和NSNumber的時(shí)候.
import Foundation
let n = NSNumber(value: UInt32(301))
let v = n as? Int8 nil(Swift 4). Swift 3會(huì)是45 (試試看!).
類和協(xié)議的組合
SE-0156:你現(xiàn)在能寫出OC這段UIViewController *在Swift中的等價(jià)代碼,比如聲明這樣 個(gè)變
,這個(gè)變 擁有實(shí)體類型并同時(shí)遵守? 協(xié)議.語法let變:某個(gè)類&協(xié)議1 &協(xié)議2.import Cocoa
protocol HeaderView {}
class ViewController: NSViewController {
let header: NSView & HeaderView
init(header: NSView & HeaderView) {
self.header = header
super.init(nibName: nil, bundle: nil)!
}
required init(coder decoder: NSCoder) {
fatalError("not implemented")
}
}
不能傳 個(gè)簡單的NSView進(jìn)去因?yàn)椴蛔袷貐f(xié)議ViewController(header: NSView())
錯(cuò)誤: argument type 'NSView' does not conform to expected type 'NSView & HeaderView'必須穿 個(gè)NSView (類)同時(shí)遵守協(xié)議
extension NSImageView: HeaderView {}
ViewController(header: NSImageView())有