Swift 4 新功能 -(一)
- 开区间
- 字符串
- 同文件内的扩展, 私有声明可见
- 智能Key path
- 编码和解码
开区间
SE-0172 带来一种新的 RangeExpression
协议和一组前缀/后缀操作符给开区间. 比如现在区间无论是上界还是下界都可以不指定.
-
无限序列
你可以用开区间来造一个无限序列, 对长期使用 enumerated() 方法的同学来说,这是一个福音,尤其是当你不想序号从0开始的时候:
let letters = ["a","b","c","d"]
let numberedLetters = zip(1..., letters)
Array(numberedLetters)
- 集合的下标
在集合的下标中用开区间的话, 集合的 startIndex
orendIndex
会“智能填充” 缺失的那一边.
let numbers = [1,2,3,4,5,6,7,8,9,10]
numbers[5...] // 取代 numbers[5..<numbers.endIndex]
打印 [6, 7, 8, 9, 10]
- 方式匹配
开区间可用于方式匹配, 比如一个 switch
语句中case
表达式 .
let value = 5
switch value {
case 1...:
print("greater than zero")
case 0:
print("zero")
case ..<0:
print("less than zero")
default:
fatalError("unreachable")
}
打印 "greater than zero"
字符串
- 多行字符串字面量
SE-0168 带来一种简洁定义多行字符串的语法,使用 ("""). 在一个多行字符串里并不需要写转义字符, 也就是说大多数文本格式 (如JSON 或 HTML) 就可以直接粘贴而无须任何转义. 结尾三引号的缩进,决定了每一行头部被裁剪的空格多少.
let multilineString = """
This is a multi-line string.
You don't have to escape "quotes" in here.
The position of the closing delimiter
controls whitespace stripping.
"""
print(multilineString)
打印
This is a multi-line string.
You don't have to escape "quotes" in here.
The position of the closing delimiter
controls whitespace stripping.
- 字符串"又双"变回一个 Collection了
SE-0163 是Swift 4
字符串模型的第一部分修正. 最大变化String
再度是一个Collection
(因为在Swift 1.x中是这样的), 比如String.CharacterView
已经被并入其父类型中. (其他view
,UnicodeScalarView
,UTF8View
, 和UTF16View
, 依旧存在.)
注意SE-0163还没完全实现并且这条建议中还有很多字符串相关的提议.
let greeting = "Hello, 😜!"
// No need to drill down to .characters
greeting.count
for char in greeting {
print(char)
}
- Substring 是字符串切片后的新类型
字符串切片现在是 Substring
类型的实例. String
和 Substring
两者都遵从 StringProtocol
. 几乎所有字符串API都在StringProtocol
所以 String
和 Substring
行为很大程度是一样的.
let comma = greeting.index(of: ",")!
let substring = greeting[..<comma]
type(of: substring)
// String API can be called on Substring
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)
结果: [127466, 127482]
- 同文件内的扩展, 私有声明可见
SE-0169 更改了访问控制规则,比如在同文件内的扩展中,原类型的private
声明也是可见的. 这种改进可让同文件内保持使用private
分割类型定义成为可能 , 减少不受欢迎的fileprivate
关键词的使用.
struct SortedArray<Element: Comparable> {
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 Person {
var name: String
}
struct Book {
var title: String
var authors: [Person]
var primaryAuthor: Person {
return authors.first!
}
}
let abelson = Person(name: "Harold Abelson")
let sussman = Person(name: "Gerald Jay Sussman")
let sicp = Book(title: "Structure and Interpretation of Computer Programs", authors: [abelson, sussman])
-
Key path
由一个根类型开始,和其下任意深度的属性链和下标名组成.
你可以写一个key path由一个反斜杠开始: \ Book
.title
. 每个类型自动获取一个 [keyPath: …]
下标可以设置或获取指定key path的值.
sicp[keyPath: \Book.title]
// Key paths can to drill down and work for computed properties
sicp[keyPath: \Book.primaryAuthor.name]
- Key path 是可被存储和操作的对象. 比如, 你可以给一个key path加上额外字段深入到作者.
let authorKeyPath = \Book.primaryAuthor
type(of: authorKeyPath)
let nameKeyPath = authorKeyPath.appending(path: \.name) // you can omit the type name if the compiler can infer it
sicp[keyPath: nameKeyPath]
- 下标Key path
Key paths 也支持下标. 如此一来可以非常便捷的深入到数组或字典这些集合类型中. 不过这功能在当前snapshot
& xcode 9 beta
还未实现.
//sicp[keyPath: \Book.authors[0].name]
// INTERNAL ERROR: feature not implemented: non-property key path component
压缩化 和 序列化
SE-0166: Swift Archival & Serialization 定义了一种为任意Swift类型 (class, struct, 和 enum) 来描述自身如何压缩和序列化的方法. 类型可遵从 Codable
协议让自身可(解)压缩.
大多数情况下添加Codable
协议就可以让你的自定义类型完美解压缩, 因为编译器可以生成一个默认的实现,前提是所有成员类型都是Codable
的. 当然你可以覆盖默认方法如果需要优化自定义类型的编码. 这个说来话长 — 还请研读SE-0166.
// Make a custom type archivable by conforming it (and all its members) to Codable
struct Card: Codable {
enum Suit: String, Codable {
case clubs, spades, hearts, diamonds
}
enum Rank: Int, Codable {
case ace = 1, two, three, four, five, six, seven, eight, nine, ten, jack, queen, king
}
var suit: Suit
var rank: Rank
}
let hand = [Card(suit: .clubs, rank: .ace), Card(suit: .hearts, rank: .queen)]
- 编码
一旦有一个Codable
值, 你要把它传递给一个编码器以便压缩 .
利用Codable
协议的基础设施可以写自己的编解码器, 不过Swift同时为JSON提供一个内置的编解码器 (JSONEncoder
和 JSONDecode
r) 和属性列表 (PropertyListEncoder
和 PropertyListDecoder
). 这些是在 SE-0167 中定义的. NSKeyedArchiver
同样支持所有的 Codable
类型.
import Foundation
var encoder = JSONEncoder()
// JSONEncoder提供的可定制化属性
encoder.dataEncodingStrategy
encoder.dateEncodingStrategy
encoder.nonConformingFloatEncodingStrategy
encoder.outputFormatting
encoder.userInfo
let jsonData = try encoder.encode(hand)
String(data: jsonData, encoding: .utf8)
- 解码
let decoder = JSONDecoder()
let decoded = try decoder.decode([Card].self, from: jsonData)
[{clubs, ace}, {hearts, queen}]
Swift 4新功能 二
英文 By Ole Begemann 中文 by 小波
相关视频