Swift4 新功能

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())有

你可能感兴趣的:(Swift4 新功能)