What's New in Swift 5

logo

原文

好消息!Swift 5 最终正式版在Xcode 10.2 中可使用。这个版本带来稳定的ABI和对一些期待已久的特性的完善。

这个教程中,你将学到关于Swift 5重要的改变。Swift 5需要Xcode 10.2,所以在开始之前确定你已经安装了Xcode 10.2.

开始

Swift 5 是源码兼容Swift 4.2,但不是二进制兼容Swift之前的版本。不过由于稳定的ABI在未来的版本中将是二进制兼容Swift 5。

ABI稳定能够二进制兼容不同Swift版本在app和库之间编译。Swift标准库和runtime被嵌入到操作系统中,所以在任何平台app在发布的时候不需要拷贝这些库。这样就更好的实现工具去耦合和系统集成。

你也需要稳定的ABI去发布二进制库在多个Swift版本中工作。这需要模块格式稳定,稳定的模块文件包含编译者库的公共接口。

在教程的每个章节你将发现Swift进展提议号如[SE-0001].通过浏览每个提议链接你将能学到更多关于Swift5 新的修改。

最好的方法是跟着这个教程试着在playground中尝试这些新的特性。

启动Xcode 10.2 并选择File->New->Playground.设置平台为iOS,模板选择Blank。命名并保存在任意你想保存的地方。是时候开始了。

注:需要快速回忆Swif 4.2 更新了什么?查看Swift 4.2 链接教程:What’s New in Swift 4.2?

语言改进

在Swift 5中有许多语言特性,例如动态可赎回类型,操作未来枚举等等。

测试复数

在Swift 4.2中,你确定一个数是偶数还是奇数,正常是如下操作:

1
2
3
4
5
let firstNumber = 4
let secondNumber = 2
if secondNumber != 0 && firstNumber % secondNumber == 0 {
print("\(secondNumber) * \(firstNumber / secondNumber) = \(firstNumber)")
}

这段代码如何完成工作的:

  • 1.检查 secondNumber 不为0.
  • 2.检查 firstNumbersecondNumber 返回余数是否为0.
  • 3.执行除操作。

你必须检查 secondNumber 不为0. 如果为0使用%将为抛出错误。

Swift 5简化了实现通过添加 isMultiple(of:)BinaryInteger [SE-0225]:

1
2
3
if firstNumber.isMultiple(of: secondNumber) {
print("\(secondNumber) * \(firstNumber / secondNumber) = \(firstNumber)")
}

isMultiple(of:) 改方法甚至你传0也能正常工作。返回结果变的更干净整洁。

转义原生字符串

Swift 4.2 在字符串中表示反斜杠和引号需要使用转义序列:

1
2
3
4
5
6
let escape = "You use escape sequences for \"quotes\"\\\"backslashes\" in Swift 4.2."
let multiline = """
You use escape sequences for \"\"\"quotes\"\"\"\\\"\"\"backslashes\"\"\"
on multiple lines
in Swift 4.2.
"""

Swift 5 添加源字符串。你只要在字符串头部和尾部添加#,这样使用反斜杠和引号就不会有任何问题了[SE-0200]:

1
2
3
4
5
6
7

let raw = #"You can create "raw"\"plain" strings in Swift 5."#
let multiline = #"""
You can create """raw"""\"""plain""" strings
on multiple lines
in Swift 5.
"""#

当要在字符串中插入字符串,你必须在反斜杠后面添加#号:

1
2
let track = "Nothing Else Matters"
print(#"My favorite tune\song is \#(track)."#)

有一些情况是当你需要在字符串开头与结尾使用多个#号:

1
let hashtag = ##"You can use the Swift "hashtag" #swift in Swift 5."##

在上面的代码中,你添加##在字符串头尾做标志,这样你能表示#号里面的字符串。字符串开头的#号数量必须和结尾的#号数量想匹配。

在Swift 4.2,你转义反斜杠在正则表达式表示如下:

1
2
3
4
5
6
7
8
9
// 1
let versions = "3 3.1 4 4.1 4.2 5"
let range = NSRange(versions.startIndex..., in: versions)
// 2
let regex = try! NSRegularExpression(pattern: "\\d\\.\\d")
// 3
let minorVersions = regex.matches(in: versions, range: range)
// 4
minorVersions.forEach { print(versions[Range($0.range, in: versions)!]) }

这些代码如何工作的:

  1. 声明versions 定义range 覆盖整个versions字符串
  2. 定义正则表达式来匹配所有在versions中Swift次要版本
  3. 使用matches(in:options:range:)方法来匹配次要版本
  4. 使用ranges从versions中获取次要版本

Swift 5 简化了原生字符串的正则表达式:

1
let regex = try! NSRegularExpression(pattern: #"\d\.\d"#)

在这个代码中,你少些了一半的反斜杠,因为在原生字符串中你不需要转义反斜杠。

swiftlog

使用新的字符属性

Swift 4.2 当这种一般的字符串操作任务需要很多操作代码:

1
2
3
4
let id = "ID10"
var digits = 0
id.forEach { digits += Int(String($0)) != nil ? 1 : 0 }
print("Id has \(digits) digits.")

在这个代码中,通过对每一个字符转为整型你想确定id字符串中有多少个数字。

然而,Swift 5 添加为字符添加了属性使得字符更容易使用[SE-0221]:

1
id.forEach { digits += $0.isNumber ? 1 : 0 }

在这个示例中,你使用isNumber去检测是否每个字符都为数字。看一看新添加其他你能使用的属性。

使用新的Unicode Scalar 属性

在 Swift 4.2,你实现文本处理使用Unicode scalar算法如下:

1
2
3
4
5
6
let username = "bond007"
var letters = 0
username.unicodeScalars.forEach {
letters += (65...90) ~= $0.value || (97...122) ~= $0.value ? 1 : 0
}
print("Username has \(letters) letters.")

在这个代码里,通过检测每个字符的unicode编码来表示小写或者大写的字母计算username中有多少个字母。

Swift 5 添加了Unicode编码属性,简化了文本处理[SE-0211]:

1
username.unicodeScalars.forEach { letters += $0.properties.isAlphabetic ? 1 : 0 }

这段代码中,你使用isAlphabetic属性来检测每个字符是否为字母,这个提案链接展示了所有你能查看的属性。

移除子序列

在Swift 4.2 从序列中返回子序列需要自定义方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
extension Sequence {
func remove(_ s: String) -> SubSequence {
guard let n = Int(s) else {
return dropLast()
}
return dropLast(n)
}
}

let sequence = [5, 2, 7, 4]
sequence.remove("2") // [5, 2]
sequence.remove("two") // [5, 2, 7]

在这个代码中,如果s是一个数字或者是最后一个元素调用remove(_:)方法来移除最后的n个元素。

Swift 5 替换 SubSequence 为具体的类型在序列中[SE-0234]:

1
2
3
4
5
6
7
8
extension Sequence {
func remove(_ s: String) -> [Element] {
guard let n = Int(s) else {
return dropLast()
}
return dropLast(n)
}
}

在这个代码中,remove(_ :)方法返回的是[Element]类型,因为 dropLast()和 dropLast(_:)方法返回的是[Element]类型。

字典的更新

Swift 5 带来了我们期待已久对字典的改进:

压缩字典

Swift 4.2 使用 mapValues,filter 和 reduce 去过滤 nil值从字典中如下:

1
2
3
4
5
let students = ["Oana": "10", "Nori": "ten"]
let filterStudents = students.mapValues(Int.init)
.filter { $0.value != nil }
.mapValues { $0! }
let reduceStudents = students.reduce(into: [:]) { $0[$1.key] = Int($1.value) }

这个代码使用mapValues、filter和reduce 来确定学生的有效等级。两种处理需要多个字典传递,使你代码复杂化了。

Swift 5 使用compactMapValues(_:)方法来更搞笑的处理[SE-0218]:

1
let mapStudents = students.compactMapValues(Int.init)

完成相同的事情使用更少的代码,整洁!

重命名字典字面值

Swift 4.2 使用 DictionaryLiteral 类型来声明字典如下:

1
let pets: DictionaryLiteral = ["dog": "Sclip", "cat": "Peti"]

DictionaryLiteral 不是一个字典或字面值,它是一个键值对表。

Swift 5 重命名 DictionaryLiteral 为 KeyValuePairs [SE-0214]:

1
let pets: KeyValuePairs = ["dog": "Sclip", "cat": "Peti"]

Numeric协议更新

Swift 4.2 实现vectors的Numeric协议:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
// 1
struct Vector {
let x, y: Int

init(_ x: Int, _ y: Int) {
self.x = x
self.y = y
}
}

// 2
extension Vector: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
x = value
y = value
}
}

// 3
extension Vector: Numeric {
var magnitude: Int {
return Int(sqrt(Double(x * x + y * y)))
}

init?<T>(exactly value: T) {
x = value as! Int
y = value as! Int
}

static func +(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x + rhs.x, lhs.y + rhs.y)
}

static func +=(lhs: inout Vector, rhs: Vector) {
lhs = lhs + rhs
}

static func -(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x - rhs.x, lhs.y - rhs.y)
}

static func -=(lhs: inout Vector, rhs: Vector) {
lhs = lhs - rhs
}

static func *(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x * rhs.y, lhs.y * rhs.x)
}

static func *=(lhs: inout Vector, rhs: Vector) {
lhs = lhs * rhs
}
}

// 4
extension Vector: CustomStringConvertible {
var description: String {
return "(\(x) \(y))"
}
}

这些代码的工作流程如下:

  1. 为Vector声明 x ,y 属性和 init(_ :_ :) 构造方法。
  2. 实现 init(integerLiteral:) 为了Numeric协议需要Vector遵循ExpressibleByIntegerLiteral协议。
  3. Vector 遵循Numeric协议通过定义magnitude变量,声明init(exactly:)方法,实现+(lhs:rhs:), +=(lhs:rhs:), -(lhs:rhs:), -=(lhs:rhs:), *(lhs:rhs:), *=(lhs:rhs:).等方法。
  4. Vector遵循CustomStringConvertible协议来实现description变量。

以上的代码能够使得你使用vectors更容易实现一些操作:

1
2
3
4
5
6
var first = Vector(1, 2) // (1,2)
let second = Vector(3, 4) // (3,4)
let third = first + second // (4,6)
first += second // (4,6)
let fourth = first - second // (1,2)
first -= second // (1,2)

Swift 5 实现AdditiveArithmetic协议为vectors,因为你不能定义2D矢量的向量积[SE-0233],它不需要实现ExpressibleByIntegerLiteral协议。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
extension Vector: AdditiveArithmetic {
static var zero: Vector {
return Vector(0, 0)
}

static func +(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x + rhs.x, lhs.y + rhs.y)
}

static func +=(lhs: inout Vector, rhs: Vector) {
lhs = lhs + rhs
}

static func -(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x - rhs.x, lhs.y - rhs.y)
}

static func -=(lhs: inout Vector, rhs: Vector) {
lhs = lhs - rhs
}
}

这个代码里,Vector遵循了AdditiveArithmetic协议,定义了zero属性,实现了+(lhs:rhs:), +=(lhs:rhs:), -(lhs:rhs:), -=(lhs:rhs:)方法。

dog

字符串插入更新

Swift 4.2 实现字符串插入通过分割字符串插入:

1
2
3
4
5
6
7
let language = "Swift"
let languageSegment = String(stringInterpolationSegment: language)
let space = " "
let spaceSegment = String(stringInterpolationSegment: space)
let version = 4.2
let versionSegment = String(stringInterpolationSegment: version)
let string = String(stringInterpolation: languageSegment, spaceSegment, versionSegment)

这段代码,编译器首先进行逐个分割然后通过init(stringInterpolationSegment:)方法插入,然后在将所有分割进行组合通过init(stringInterpolation:)方法。

Swift 5 通过不同的方法进行实现[SE-0228]:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 1
var interpolation = DefaultStringInterpolation(
literalCapacity: 7,
interpolationCount: 1)
// 2
let language = "Swift"
interpolation.appendLiteral(language)
let space = " "
interpolation.appendLiteral(space)
let version = 5
interpolation.appendInterpolation(version)
// 3
let string = String(stringInterpolation: interpolation)

这些代码工作如下:

  1. 定义一个 DefaultStringInterpolation 类型的实例通过确定的容量和插入数量值。
  2. 调用 appendLiteral(_ :) 或者 appendInterpolation(_ :) 去添加字面量和插入值到interpolation。
  3. 生成最终的插入字符串通过调用init(stringInterpolation:)方法。

枚举的新操作

Swift 4.2 不需要处理新添加的枚举类,因为如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1
enum Post {
case tutorial, article, screencast, course
}

// 2
func readPost(_ post: Post) -> String {
switch post {
case .tutorial:
return "You are reading a tutorial."
case .article:
return "You are reading an article."
default:
return "You are watching a video."
}
}

// 3
let screencast = Post.screencast
readPost(screencast) // "You are watching a video."
let course = Post.course
readPost(course) // "You are watching a video."

以上代码执行如下操作:

  1. 定义网站上所有博客文章类型
  2. 执行switch穷举,添加default。
  3. 处理 .screencast 和 .course 用default 因为 screencasts 和 courses 是 视频类型。

在Swift 4.2中处理 podcasts类型操作如下:

1
2
3
4
5
6
enum Post {
case tutorial, article, podcast, screencast, course
}

let podcast = Post.podcast
readPost(podcast) // "You are watching a video."

在这段代码中,你处理 .podcast 使用default,虽然podcasts 不是视频类型,Swift 4.2 不会警告你因为switch被穷举了。

Swift 5 中新增了这种情况类型[SE-0192]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func readPost(_ post: BlogPost) -> String {
switch post {
case .tutorial:
return "You are reading a tutorial."
case .article:
return "You are reading an article."
@unknown default:
return "You are reading a blog post."
}
}

readPost(screencast) // "You are reading a blog post."
readPost(course) // "You are reading a blog post."
readPost(podcast) // "You are reading a blog post."

在这段代码中,你标记default为@unknown,Swift会警告提示你switch并未穷举,default处理.screencast,.course 和 .podcast 因为screencasts,courses和podcasts是博客文章。

sun

新增Result类再标准库中

Swift 5 添加 Result 类到标准库[SE-0235]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 1
enum ConnectionError: Error {
case noNetwork, noDatabase
}

// 2
let networkSuccess = Result<String, ConnectionError>.success("Network connected!")
let databaseSuccess = Result<String, ConnectionError>.success("Database connected!")
let networkFailure = Result<String, ConnectionError>.failure(.noNetwork)
let databaseFailure = Result<String, ConnectionError>.failure(.noDatabase)
let sameSuccess = networkSuccess == databaseSuccess
let sameFailure = networkFailure == databaseFailure
let success: Set = [networkSuccess, databaseSuccess]
let failure: Set = [networkFailure, databaseFailure]
let successDictionary = [
networkSuccess: try! networkSuccess.get(),
databaseSuccess: try! databaseSuccess.get()
]
let failureDictionary = [
networkFailure: ConnectionError.noNetwork,
databaseFailure: ConnectionError.noDatabase
]

这段代码执行效果如下:

  1. 声明一个普通的连接错误枚举
  2. 比较连接结果,添加他们到集合中,用这些集合作为字典的key值,因为Result实现了Equatable和Hashable协议。

Never 遵循 Equatable和Hashable协议

Swift 5 让Never遵循Equatable 和 Hashable协议[SE-0215]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let alwaysSucceeds = Result<String, Never>.success("Network connected!")
let neverFails = Result<String, Never>.success("Database connected!")
let alwaysFails = Result<Never, ConnectionError>.failure(.noNetwork)
let neverSucceeds = Result<Never, ConnectionError>.failure(.noDatabase)
let sameValue = alwaysSucceeds == neverFails
let sameError = alwaysFails == neverSucceeds
let alwaysSuccess: Set = [alwaysSucceeds, neverFails]
let alwaysFailure: Set = [alwaysFails, neverSucceeds]
let alwaysSuccessDictionary = [
alwaysSucceeds: try! alwaysSucceeds.get(),
neverFails: try! neverFails.get()
]
let alwaysFailureDictionary = [
alwaysFails: ConnectionError.noNetwork,
neverSucceeds: ConnectionError.noDatabase
]

在这段代码中,你定义连接结果为总返回有值或者错误,比较他们,添加他们到集合中,用他们做字典的key。

动态调用类型

Swift 5 定义动态调用类型交互操作脚本语言类似Python和Ruby[Se-2016]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 1
@dynamicCallable
class DynamicFeatures {
// 2
func dynamicallyCall(withArguments params: [Int]) -> Int? {
guard !params.isEmpty else {
return nil
}
return params.reduce(0, +)
}

func dynamicallyCall(withKeywordArguments params: KeyValuePairs<String, Int>) -> Int? {
guard !params.isEmpty else {
return nil
}
return params.reduce(0) { $1.key.isEmpty ? $0 : $0 + $1.value }
}
}

// 3
let features = DynamicFeatures()
features() // nil
features(3, 4, 5) // 12
features(first: 3, 4, second: 5) // 8

以上代码工作如下:

  1. 标记DynamicFeatures类为@dynamicCallable使他为动态调用类型.
  2. 让DynamicFeatures类遵循@dynamicCallable,实现dynamicallyCall(withArguments:)和 dynamicallyCall(withKeywordArguments:)方法。
  3. 按常规语法去使用features,编译器会调用dynamicallyCall(withArguments:)和 dynamicallyCall(withKeywordArguments:)方法。

Swift包管理更新

Swift 5 添加一些新的特性到Swift包管理中:

平台部署设置:

Swift 5 在Package.swift中允许你定义目标版本的需要的平台版本最小值:

1
2
3
4
5
6
let package = Package(name: “Package”, platforms: [
.macOS(.v10_14),
.iOS(.v12),
.tvOS(.v12),
.watchOS(.v5)
])

你使用 macOS(), iOS(), tvOS() 和 watchOS() 这些支持的平台设置最低需要的版本在package中。

目标编译设置

Swift 5 声明 目标特性编译设置在Package.swift,他们自定义如果管理调用编译工具在目标编译期间[SE-0238].

镜像依赖

Swift 5 带来了镜像依赖在Swift包管理中[SE-0219].

1
swift package config set-mirror --package-url <package> --mirror-url <mirror>

镜像能够让你获得依赖库,甚至原始资源不可获取或是被删除了。

set-mirror 更新依赖库通过镜像,替换其他所有的依赖。

使用 unset-mirror 去移除镜像依赖库:

1
2
3
swift package config unset-mirror --package-url <package>
swift package config unset-mirror —mirror-url <mirror>
swift package config unset-mirror --all

各种零碎的东西

Swift 5添加了一些其他大量的特性和改进:

添加Codable Ranges

Swift 5 添加 Codable协议支持ranges[SE-0239]:

1
2
3
4
5
let temperature = 0...10
let encoder = JSONEncoder()
let data = try! encoder.encode(temperature)
let decoder = JSONDecoder()
let temperatureRange = try! decoder.decode(ClosedRange<Int>.self, from: data)

你使用JSONEncoder将temperature进行编码,使用JSONDecoder对data进行解码,因为Swift 5默认ranges实现了Codable协议。

整合内嵌可选类型

Swift 4.2 创建内嵌可以选类型使用try?:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
extension Int {
// 1
enum DivisionError: Error {
case divisionByZero
}

// 2
func divideBy(_ number: Int) throws -> Int {
guard number != 0 else {
throw DivisionError.divisionByZero
}
return self / number
}
}

// 3
let number: Int? = 10
let division = try? number?.divideBy(2)
if let division = division,
let final = division {
print(final)
}

这段代码操作如下:

  1. 扩展Int添加DivisionError枚举
  2. divideBy(_:) 方法如果number为0抛出.divisionByZero
  3. 两次解包division,因为他是一个Int??类型

Swift 5 不同的方式处理[SE-0230]:

1
2
3
if let division = division {
print(division)
}

try? 在Swift 5 不会创建内嵌可选值,所以你只要解包division一次就够他是Int?类型。

从集合中移除自定义的位置值

在Swift 4.2中你从集合中可以使用定制的位置值:

1
2
3
4
5
6
7
8
9
10
11
12
13
extension Array {
var first: Element? {
return !isEmpty ? self[count - 1] : nil
}

var last: Element? {
return !isEmpty ? self[0] : nil
}
}

let names = ["Cosmin", "Oana", "Sclip", "Nori"]
names.first // "Nori"
names.last // "Cosmin"

在这段代码中,first返回names数组最后一个元素,last返回数组第一个元素。

两种计算属性被期望不能使用,所以Swift 5从集合中将他们移除[SE-0232].

Identity Key Paths

Swift 4.2 使用.self获取值:

1
2
3
4
5
6
7
8
9
10
11
class Tutorial {
let title: String
let author: String
init(title: String, author: String) {
self.title = title
self.author = author
}
}

var tutorial = Tutorial(title: "What's New in Swift 5.0?", author: "Cosmin Pupaza")
tutorial.self = Tutorial(title: "What's New in Swift 5?", author: "Cosmin Pupăză")

这段代码,你用.self 一下子修改tutorial的title和author.

Swift 5 添加了 identity key paths来使用[SE-0227]:

1
2
3
tutorial[keyPath: \.self] = Tutorial(
title: "What's New in Swift 5?",
author: "Cosmin Pupăză")

这段代码里,你用.self 去更新tutorial

强制初始化字面值

在Swift 5,字面值初始化如果类型符合字面值协议强制字面值类型[SE-0213]:

1
let value = UInt64(0xFFFF_FFFF_FFFF_FFFF)

在Swift 4.2中,上面这行代码在编译时会报溢出错误。

编译配置更新

Swift 4.2 使用 >= 做编译条件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let favoriteNumber = 10
var evenNumber = true

#if !swift(>=5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

#if !compiler(>=5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

这些条件判断Swift版本是否大于等于5,如果条件符合就编译这些代码。

Swift 5 添加 < 来简化条件[SE-0224]:

1
2
3
4
5
6
7
8
9
10
11
#if swift(<5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

#if compiler(<5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif

使用可变参数作为枚举的关联值

你能够使用可变参数作为枚举case的关联值在Swift 4.2中:

1
2
3
4
enum BlogPost {
case tutorial(_: String...)
case article(_: String...)
}

你使用String…做为教程和文章的详情,在Swift 5中已经不能使用,你需要使用数组替代了:

1
2
3
4
enum BlogPost {
case tutorial([String])
case article([String])
}

这次你使用[String]设置教程和文章详情。

取消字符串索引编码偏移

Swift 4.2 字符串是使用UTF-16编码,结果encodeOffset返回一个UIF-16的字符串偏移:

1
2
let swiftVersion = "Swift 4.2"
let offset = swiftVersion.endIndex.encodedOffset

这里得到swiftVersion的endIndex的Offset,在Swift 5中使用UIF-8编码是不起作用的,所以Swift 5替换encodedOffset为utf16Offset(in:)去处理这个情况[SE-0241]:

1
2
let swiftVersion = "Swift 5"
let offset = swiftVersion.endIndex.utf16Offset(in: swiftVersion)

新指针方法

Swift 5 添加 withContiguousStorageIfAvailable(_ :)到Sequence 和 withContiguousMutableStorageIfAvailable(_ :) 到 MutableCollection 提供通用的实现withUnsafeBufferPointer(_ :) 和withUnsafeMutableBufferPointer(_ :)方法在协议扩展中[SE-0237].

SIMD 矢量更新

Swift 5 增加操作在SIMD类型处理器在标准库中。他们为SIMD矢量和矩阵提供低等级的支持。他们也简化了Objective-C,C和C++的实现在<simd/simd.h>头文件里[SE-0229].

尾声

翻译的水平有限,有错误的地方多多指出,翻译的不好还请谅解。。。Thanks!

您的支持将鼓励我继续创作!