Swift 5.7新特性 (上)

译自 www.hackingwithswift.com/articles/24…

更多内容欢迎关注公众号「Swift花园」

Swift 5.7 变化巨大,新特性中包括正则表达式, if let 速记语法,以及围绕 anysome 关键字的一致性改动。

在本文中,我会通过一些示例来介绍这些新特性。

解包可选型的 if let 速记

SE-命令行怎么打开0345 引入了新的速记语法,可以将可选型展开为同名的阴影变量。以后我httpclient们可以像下面这样gitlab解包了:

var name: String? = "Linda"
if let name {
    print("Hello, (name)!"
}

对比之前的写法:

if let name = name {
    print("Hello, (name)!"
}
if let unwrappedName = name {
    print("Hello, (unwrappedName)!"
}        

swift系统意:这个变化并不适用于对象swiftly内的属性,所以像下面这样的代码无法通过编译:

struct User {
    var name: String
}
let user: User? = User(name: "Linda")
if let user.name {
    print("Welcome, (user.name)!")
}

多语句闭包类型推断

SE-0326 极大地提高了 Swift 对闭包使用参数和类型推断的能力,httpwatch字符意味着我们现在可以删除许多必须明确指定输入和字符输出类型的写法。

之前 Swift 处理闭包的书写难免琐碎,但从 Swift 5.7 开始,我们可以编写如下简化的代码:

let scores = [100, 80, 85]
let results = scores.map { score in
    if score >= 85 {
        return "(score)%: Pass"
    } else {
        return "(score)%: Fail"
    }
}

在 Swift 5.7 之前则必须像下面这样书写:

let oldResults = scores.map { score -> String in
    if score >= 85 {
        return "(score)%: Pass"
    } else {
        return "(score)%: Fail"
    }
}

Clock,Instant 和 Duration

SE-0329 为 Swift 引入了一种新的标准化方式来引用时间和持续时间。它可以拆解为三个主要部分:

  • Clockhttp://www.baidu.com表了一种测量时间流逝的方式。有两个内置时钟:连续时钟在系统处于睡眠状态时也会保持时间递增,而挂起时http://www.baidu.com钟则不会。
  • Instant 代表一个精确的瞬间。
  • Durations 表示两个 Instant 之间经过了多少时间。

这个新特性对许多人来说来联想git命令到的最直接的应用就是新升级的 Task API:它现在可以用比纳秒更合理的术语来指定休眠时长:

try await Task.sleep(until: .now +  .seconds(1), clock: .continuous)

这个新 API 还有一个好处是能够指定容差,使得系统在睡眠截止日期之后能够稍等片刻,以便最大限度地提高电源效率Swift。所以,假如我们想 sleep 至少 1 秒,并且能接受它总共持续 1.5 秒,我们可以这样写:

try await Task.sleep(until: .now + .seconds(1), tolerance: .seconds(0.5), clock: .continuous)

时钟对于测量某些特定的工作也很有用字符串是什么意思。比如,我们想向用户展示文件导出过程花费了多长时间,可以使用时钟的

measure 闭包:

let clock = ContinuousClock()
let time = clock.measure {
    // complex work here
}
print("Took (time.components.seconds) seconds")

正则表达式

Swift 5.7 引入了大量与正则表达式相关的改进,这是一整套相互关联的提案,包括:

  • SE-0350 引入了新的 Regex 类型
  • SE-0351 引入了一个用于创建正命令行进入指定目录则表达式的 result builder 驱动的 DSL。
  • SE-0354 引入了使用 /.../ 而不单是 Regex 来共同创建正则表达式的方式。
  • SE-035字符间距在哪里设置7 添加了许多新的基于正则表达式的字符串处理算法。

与其他语言和平台相比,正则表达式一直是 Sw字符间距在哪里设置ift 语言一个相当大的痛点。

现在,让我们从简单的例子开始:

let message = "the cat sat on the mat"
print(message.ranges(of: "at"))
print(message.replacing("cat", with: "dog"))
print(message.trimmingPrefix("the "))

它们的真正威力在于也都接受正则表达式:

print(message.ranges(of: /[a-z]at/))
print(message.replacing(/[a-m]at/, with: "dog"))
print(message.trimmingPrefix(/The/.ignoresCase()))

如果您不熟悉正则表达式,下面是几条快速入门:

  • swift语言第一个正则表达式中,我们要求所有匹配任何小写字字符间距加宽2磅怎么设置母后跟“字符at”的子字符串的命令行快捷键范围,以便找到“cat”、“sat”和“mat”的位置。
  • 在第二个正则表达式中,我们只匹配从“a”到“m”giti的范围,所以 sat 不会被替换,它会打印字符型变量“the dog sat on the dog”。
  • 在第三个正则表达式中,我们寻找“The”,但将正则表达式修改为不区分大小写,以便匹配“httpclientthe”、“THE”等。

注意这些正则表达式是如何使用正则表达式字面量来生成的 —— 以 / 开始和结束。

除了正则表达式字面量,Sw字符间距ift 还提供了专门的 Regex 类型:

do {
    let atSearch = try Regex("[a-z]at")
    print(message.ranges(of: atSearch))
} catch {
    print("Failed to create regex")
}

这里两种方式有一个关键区别:当我们使用 Regex 从字符串创建正则表达式时,Swift命令行快捷键 必须在运行时解析字符串以找出它应该使用的实际表达式。相比之下,使用正则表达式字面量允许 Swigithub永久回家地址ft 在编译时 检查你的正则表达式:它可以验证正则表达式不包含错误,并且还可以准确了解它将包含什么匹配项。

在编译时解析你的正http://192.168.1.1登录则表达式,确保它们是有效的 —— 牛!

想知道这个差异有多强大,咱们来看下面的代码:

let search1 = /My name is (.+?) and I'm (d+) years old./
let greeting1 = "My name is Taylor and I'm 26 years old."
if let result = try search1.wholeMatch(in: greeting1) {
    print("Name: (result.1)")
    print("Age: (result.2)")
}

这会创建一个正则表达式来查找某些文本中的两个特定值,如果找到它们都会打印它们。但请注意 result 元组如何将其匹配项引用为 .1.2,因为 Swift 知道将发生哪些匹配项。 (.0 将返回整个匹配的字符串。)

事实上,正则表达式还允许我们命名匹配项,这些匹配项会流向git教程生成的匹配元组:

let search2 = /My name is (?<name>.+?) and I'm (?<age>d+) years old./
let greeting2 = "My name is Taylor and I'm 26 years old."
if let result = try search2.wholeMatch(in: greeting2) {
    print("Name: (result.name)")
    print("Age: (result.age)")
}

这种安全性对于从字符串创建的正则表达式是不可能的。

但 SwHTTPift 更进一步,你还可以从类似于 SwiftUI 代码的 DSL 语言创建正则表达式。

例如字符是什么,如果http 500我们想匹配 “我的名字是 Taylor,我 26http 500 岁” 的文本,我们可以写一个这样的正则表达式:

let search3 = Regex {
    "My name is "
    Capture {
        OneOrMore(.word)
    }
    " and I'm "
    Capture {
        OneOrMore(.digit)
    }
    " years old."
}

更棒的是,github这种 DSL 方法能够对其找到的匹配项应用转换,如果我们使用 TryCapture 而不是命令行窗口怎么打开 Capture,在捕获失败或有错误抛出时,Swift 将自动认为整个正则表达式不匹配。因此,在我们的年龄匹配的例子中,我们可以编写以下代码来将年龄字符串转换为整数swift国际结算系统

let search4 = Regex {
    "My name is "
    Capture {
        OneOrMore(.word)
    }
    " and I'm "
    TryCapture {
        OneOrMore(.digit)
    } transform: { match in
        Int(match)
    }
    Capture(.digit)
    " years old."
}

你甚至可以使用具有特定类型的变量将命名匹配组合在一起,如下所示:

let nameRef = Reference(Substring.self)
let ageRef = Reference(Int.self)
let search5 = Regex {
    "My name is "
    Capture(as: nameRef) {
        OneOrMore(.word)
    }
    " and I'm "
    TryCapture(as: ageRef) {
        OneOrMore(.digit)
    } transform: { match in
        Int(match)
    }
    Capture(.digit)
    " years old."
}
if let result = greeting.firstMatch(of: search5) {
    print("Name: (result[nameRef])")
    print("Age: (result[ageRef])")
}

在这三个选项中,我怀疑正则表达式文字会得到最广泛的使用。尽管在 Swift 6 发布之前,默认情况下对它们的支持将被禁用。你可以把 “-Xfrontend -enable-bare-命令行常用命令slash-giteeregex” 添加到 Xcode 中的 Swift Flags 设置以启用这个语法特性。

基于默认表达式的类型推github

SE-0347 扩展了 Swift 使用泛型参数类型的默认值的能力。这个特性似乎相当小众,命令行快捷键但确实重要:如果你有一个泛型类型或函数,现在可以为默认表达式提供一个具体类型。

例如,我们可能有一个函数,它从任意类型的序列中返回 count 个随机项命令行参数

func drawLotto1<T: Sequence>(from options: T, count: Int = 7) -> [T.Element] {
    Array(options.shuffled().prefix(count))
}

这允许我们使用任何类型的序列来运行swift系统命令行窗口怎么打开swift系统,例如字符串数组或者整数范围:

print(drawLotto1(from: 1...49))
print(drawLotto1(from: ["Jenny", "Trixie", "Cynthia"], count: 2))

SE-0347 允许我们为函数中的 T 参数提供一个具体类型作为默认值,同时允许我们保持使用字符串数组或任何其他序列类型的灵活性:

func drawLotto2<T: Sequence>(from options: T = 1...49, count: Int = 7) -> [T.Element] {
    Array(options.shuffled().prefix(count))
}

这样一来我们既可以使用自定命令行快捷键义序列调用函数,也可以让默认值接管:

print(drawLotto2(from: ["Jenny", "Trixie", "Cynthia"], count: 2))
print(drawLotto2())

顶级代码的并发

SE-0343 升级了 Swift 对顶级代码的支持——想想github永久回家地址 macOSgiti 命令行工具项目中的 main.swift —— 以便HTTP它支持开箱即用的并发。这个变化看起来微不足道,但为了支持它需要相当多的工作。

实践上,这个变化意味着我们可以将这样的代码直接写入 main.swift 文件:

let url = URL(string: "https://hws.dev/readings.json")!
let (data, _) = try await URLSession.shared.data(from: url)
let readings = try JSONDecoder().decode([Double].self, from: data)
print("Found (readings.count) temperature readings")

在这个变化以前,我们必须创建一个具有异步 mai命令行窗口n() 方法的 @ma命令行进入指定目录in 结构。因此说这个变化是一个不小的改进。

不透明参数声命令行进入指定目录

SE-0341 解锁字符是什么了在使用更简单泛型的地方对参数声明使用 some 的能力。

举个例子,如果我们想编写一个检查数组是否排序的函数,Swift 5.7 及更高版本允许我们这样写:

func isSorted(array: [some Comparable]) -> Bool {
    array == array.sorted()
}

[some Comparable] 参数类型意味着此函数适用于包含某种类型的元素的数组,该类型遵循 Comparable 协议,这是等效通用代码的语法糖:

func isSortedOld<T: Comparable>(array: [T]) -> Bool {
    array == array.sorted()
}

当然,我们也可以写更长的约束扩展:

extension Array where Element: Comparable {
    func isSorted() -> Bool {
        self == self.sorted()
    }
}

这种简化的泛型语法确实意味着我们不再有能力为我们的类giticomfort是什么轮胎型添加更复杂的约束,因为合成的泛型参数没有特定的名称。

重要提示: 你可以在显式泛型参数和这种新的更简单语法之间切换,而不会破坏 API。

结构化的不透明结果类型

SE-0328 拓宽了不透明结果类型可以使用的范围。

例如,我们现在可以一次返回多个不透明类型:

func showUserDetails() -> (some Equatable, some Equatable) {
    (Text("Username"), Text("@twostraws"))
}

我们还可以返回不透明类型数组:

func createUser() -> [some View] {
    let usernames = ["@frankefoster", "@mikaela__caron", "@museumshuffle"]
    return usernames.map(Text.init)
}

甚至返回一个在调用时本身返回不透明类型的函数:

func createDiceRoll() -> () -> some View {
    return {
        let diceRoll = Int.random(in: 1...6)
        return Text(String(diceRoll))
    }
}

因此,这是 Swift 进化过程中保持一致性的另一个很好的例子。

封面来字符间距加宽2磅怎么设置自 Pauline Loroy on Unsplash

更多内容欢迎关注公众号字符间距加宽2磅怎么设置「Swift花园swift是什么

发表评论

提供最优质的资源集合

立即查看 了解详情