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