Swift 5.9 有哪些新特性(一)

news2024/12/26 20:59:20

文章目录

    • 前言
    • if 和 switch 表达式
    • Value 和 Type 参数包

在这里插入图片描述

前言

虽然 Swift 6 已经在地平线上浮现,但 5.x 版本仍然有很多新功能-更简单的 if 和 switch 用法、宏、非可复制类型、自定义 actor 执行器等等都将在 Swift 5.9 中推出,再次带来了一个巨大的更新。

在本文中,将介绍这个版本中最重要的变化,提供代码示例和解释,以便可以自行尝试。需要在 Xcode 14 中安装最新的 Swift 5.9 工具链,或者使用 Xcode 15 beta。

if 和 switch 表达式

请添加图片描述
SE-0380 引入了在多种情况下将 if 和 switch 用作表达式的能力。这会产生一些在一开始可能会让人感到惊讶的语法,但总体上它确实帮助减少了语言中一些额外的语法。

作为一个简单的例子,我们可以根据条件将变量设置为“ Pass ”或“ Fail ”:

let score = 800
let simpleResult = if score > 500 { "Pass" } else { "Fail" }
print(simpleResult)

或者可以使用 switch 表达式来获取更广泛的值,就像下面这样:

let complexResult = switch score {
    case 0...300: "Fail"
    case 301...500: "Pass"
    case 501...800: "Merit"
    default: "Distinction"
}

print(complexResult)

不需要在某个地方分配结果以使用这种新的表达式语法,实际上它与 Swift 5.1 的 SE-0255 非常搭配,该特性允许我们在返回一个值的单表达式函数中省略 return 关键字。

所以,由于 if 和 switch 现在都可以作为表达式使用,我们可以编写一个像这样的函数,在所有四种可能的情况下都不使用 return 关键字:

func rating(for score: Int) -> String {
    switch score {
    case 0...300: "Fail"
    case 301...500: "Pass"
    case 501...800: "Merit"
    default: "Distinction"
    }
}

print(rating(for: score))

你可能会认为这个特性使得 if 更像三元条件运算符,至少在某种程度上是对的。例如,我们可以像这样编写之前的简单 if 条件:

let ternaryResult = score > 500 ? "Pass" : "Fail"
print(ternaryResult)

然而,它们并不完全相同,特别是有一个地方可能会让你困惑 - 你可以在下面的代码中看到:

let customerRating = 4
let bonusMultiplier1 = customerRating > 3 ? 1.5 : 1
let bonusMultiplier2 = if customerRating > 3 { 1.5 } else { 1.0 }

这两个计算都产生了一个值为 1.5 的 Double,但是注意每个计算的备选值:对于三元选项,是写了 1,而对于 if 表达式,是写了 1.0。

这样做是有原因的:当使用三元运算符时,Swift 同时检查两个值的类型,因此自动将 1 视为 1.0,而对于 if 表达式,两个选项是独立进行类型检查的:如果我们在一个情况下使用 1.5,在另一个情况下使用 1,那么我们将返回一个 Double 和一个 Int,这是不允许的。

Value 和 Type 参数包

请添加图片描述

SE-0393、SE-0398 和 SE-0399 结合在一起形成了 Swift 中使用可变泛型的一系列改进的复杂结构。

这是一个相当高级的特性,用一种能够吸引大多数人注意的方式概括一下:这几乎肯定意味着 Swift 中的旧的 10 个视图限制即将消失。

这些提案解决了 Swift 中一个重要的问题,即泛型函数需要指定数量的类型参数。这些函数仍然可以接受可变参数,但最终仍然必须使用相同的类型。

举个例子,我们可以有三个不同的结构体,表示程序的不同部分:

struct FrontEndDev {
    var name: String
}

struct BackEndDev {
    var name: String
}

struct FullStackDev {
    var name: String
}

在实际情况中,这些结构体可能具有更多使它们成为独特类型的属性,但你可以理解这个例子 - 存在三种不同的类型。

我们可以这样创建这些结构体的实例:

let johnny = FrontEndDev(name: "Johnny Appleseed")
let jess = FrontEndDev(name: "Jessica Appleseed")
let kate = BackEndDev(name: "Kate Bell")
let kevin = BackEndDev(name: "Kevin Bell")

let derek = FullStackDev(name: "Derek Derekson")

当需要开始工作时,我们可以使用以下简单的函数将开发人员配对:

func pairUp1<T, U>(firstPeople: T..., secondPeople: U...) -> ([(T, U)]) {
    assert(firstPeople.count == secondPeople.count, "You must provide equal numbers of people to pair.")
    var result = [(T, U)]()

    for i in 0..<firstPeople.count {
        result.append((firstPeople[i], secondPeople[i]))
    }

    return result
}

该函数使用两个可变参数接收一组第一组人和一组第二组人,并将它们作为数组返回。

现在我们可以使用它将可以一起开展后端和前端工作的程序员配对:

let result1 = pairUp1(firstPeople: johnny, jess, secondPeople: kate, kevin)

到目前为止,这些都是老的内容,现在我们开始进入有趣的部分:假设 Derek 是一个全栈开发人员,可以作为后端开发人员或前端开发人员工作。然而,如果我们尝试使用 johnny, derek 作为第一个参数,Swift 将拒绝构建我们的代码 - 它需要所有第一组人和第二组人的类型相同。

解决这个问题的一种方法是使用 Any 抛弃所有类型信息,但是参数包使我们能够更加优雅地解决这个问题。

刚开始时,语法可能会有点复杂,所以我先展示代码,然后再解释它。请看以下代码:

func pairUp2<each T, each U>(firstPeople: repeat each T, secondPeople: repeat each U) -> (repeat (first: each T, second: each U)) {
    return (repeat (each firstPeople, each secondPeople))
}

这里有四个独立的部分,我们逐一来解释:

  • <each T, each U> 创建了两个类型参数包,T 和 U。
  • repeat each T 是一个参数包展开,它将参数包展开为实际值 - 这相当于 T...,但避免了使用 ... 作为运算符时产生的某些混淆。
  • 返回类型表示我们将返回 T 和 U 的成对程序员元组的重复。
  • 我们的 return 关键字才是真正起作用的地方:它使用参数包展开表达式从 T 中取一个值,从 U 中取一个值,将它们放在返回值中组合起来。

返回类型自动确保的 T 和 U 类型具有相同的结构 - 具有相同数量的内部项。因此,与我们在第一个函数中使用的 assert() 不同,如果尝试传入两组不同大小的数据,Swift 将简单地发出编译器错误。

有了这个新函数,我们现在可以将 Derek 与其他开发人员配对,例如:

let result2 = pairUp2(firstPeople: johnny, derek, secondPeople: kate, kevin)

实际上,我们实现了一个简单的 zip() 函数,这意味着我们可以写出这样的荒谬代码:

let result3 = pairUp2(firstPeople: johnny, derek, secondPeople: kate, 556)

它尝试将 Kevin 与数字 556 配对,显然是没有意义的。这就是参数包的优势所在,因为我们可以定义以下协议:

protocol WritesFrontEndCode { }
protocol WritesBackEndCode { }

然后添加一些遵循关系:

  • FrontEndDev 应该遵循 WritesFrontEndCode
  • BackEndDev 应该遵循 WritesBackEndCode
  • FullStackDev 应该同时遵循 WritesFrontEndCodeWritesBackEndCode

现在,可以给我们的类型参数包添加约束:

func pairUp3<each T: WritesFrontEndCode, each U: WritesBackEndCode>(firstPeople: repeat each T, secondPeople: repeat each U) -> (repeat (first: each T, second: each U)) {
    return (repeat (each firstPeople, each secondPeople))
}

这意味着只有合理的配对才能发生 - 无论是否是全栈开发人员,我们始终会得到一个能够编写前端代码的人与一个能够编写后端代码的人配对。

为了让你更容易理解,我们在 SwiftUI 中也有类似的情况。我们经常希望能够创建具有多个子视图的视图,如果我们只使用单一的视图类型(例如 Text),那么类似于 Text... 的写法将非常好用。但是,如果我们希望有一些文本,然后是图像,然后是按钮等等 - 任何非均匀布局都将不可能实现。

尝试使用 AnyView... 或类似的方式来抹除类型会丢失所有类型信息,因此在 Swift 5.9 之前,通过创建大量函数重载来解决此问题。例如,SwiftUI 的视图构建器具有 buildBlock() 重载,可以组合两个视图、三个视图、四个视图等等,一直到 10 个视图 - 但没有更多,因为它们需要划定一个限制。

因此,在 SwiftUI 中存在 10 个视图的限制。希望这个限制在即将发布的 Swift 5.9 中消失。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/652425.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

矩阵补全文献汇总

[1] Nguyen L T , Kim J , Shim B .Low-Rank Matrix Completion: A Contemporary Survey[J].IEEE Access, 2019, PP(99):1-1.DOI:10.1109/ACCESS.2019.2928130. 几根棒子的一篇工作。基本结构可以借鉴。 适用于秩未知的矩阵补全文献汇总 [1] Fornasier M , Rauhut H , Ward…

报表岗位如何快速升职加薪?卷的心态要放平,工具要选对!

最近下班时一直看到做报表的部门每个人埋头苦干&#xff0c;不用说&#xff0c;这是又在忙半年度报告了。 现在&#xff0c;报表内卷现象十分严重&#xff0c;大家可能用的是一样的数据集&#xff0c;虽说每个人输出的报告可能结果差异不大&#xff0c;但懂得怎么利用工具&…

在HR眼里,IE证书早就不值钱了

大家好&#xff0c;我是老杨。 最近项目实在是忙&#xff0c;内容都写的少了一些&#xff0c;真的是有点力不从心的意思&#xff0c;人年纪大了&#xff0c;比不起当初年轻的自己了 和同事领导在一块儿的时间越多&#xff0c;就免不了聊到今年的就业环境。 我不提&#xff0…

Vue中如何进行代码编辑器与实时预览?

Vue中如何进行代码编辑器与实时预览&#xff1f; 在现代Web应用程序中&#xff0c;代码编辑器和实时预览已经成为了必不可少的一部分。Vue作为一款流行的JavaScript框架&#xff0c;也提供了一些工具和库&#xff0c;方便开发者在Vue中集成代码编辑器和实时预览功能。本文将介…

基于Eclipse+Java+Swing+Mysql实现超市销存管理系统

基于EclipseJavaSwingMysql实现超市销存管理系统 一、系统介绍二、功能展示1.登陆2.整体页面3.进货4.售货5.查询6、退出系统 三、数据库四、其它1.其他系统实现五.获取源码 一、系统介绍 系统实现了&#xff1a;商品进货、商品销售、库存查询 、进货查询、 售货查询、退出系统…

Date类(Java)

文章目录 1. 介绍2. 分析3. 方法3.1 Constructor()3.2 getTime()3.3 compareTo()3.4 equals() 1. 介绍 A. 类介绍&#xff1a;类Data表示特定的瞬间&#xff0c;可以精确到毫秒  Date类 有两个其他的函数。它允许把日期解释为年、月、日、小时、分钟和秒值  从 JDK 1.1 开始&…

Python自动化测试的配置层实现方式对标与落地 | 京东云技术团队

Python中什么是配置文件&#xff0c;配置文件如何使用&#xff0c;有哪些支持的配置文件等内容&#xff0c;话不多说&#xff0c;让我们一起看看吧~ 1 什么是配置文件&#xff1f; 配置文件是用于配置计算机程序的参数和初始化设置的文件&#xff0c;如果没有这些配置程序可能…

Vue中如何进行数据可视化关系图展示(如关系图谱)

Vue中如何进行数据可视化关系图展示&#xff08;如关系图谱&#xff09; 随着数据分析和可视化技术的发展&#xff0c;越来越多的应用开始使用关系图谱来展示数据之间的关系。在Vue中&#xff0c;我们可以使用第三方库Vis.js来实现关系图谱的展示&#xff0c;并通过Vue组件来进…

Java网络开发(Tomcat同步数据分页)—— 用Jsp语法 到 实现数据的分页展示 到 只看自己的数据 + 模糊查询 迭代升级

目录 引出0.jsp的使用和语法 & 报错和解决&#xff08;1&#xff09;后端共享&#xff0c;前端获取 ${pageInfo}&#xff08;2&#xff09;如果想获取pageInfo这个对象的某个属性值&#xff0c;用 点 属性 ${pageInfo.pages}&#xff08;3&#xff09;如果想回传&#xff…

java 学生信息管理系统Myeclipse开发mysql数据库web结构jsp编程计算机网页项目

一、源码特点 java 学生信息管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

IDEA执行Maven命令

在工作区的最右侧&#xff0c;IntelliJ IDEA 为我们提供了一个十分实用的窗口&#xff1a;Maven 工具窗口&#xff0c;通过它我们几乎可以完成所有与 Maven 相关的操作。 在 Maven 工具窗口中&#xff0c;我们可以通过以下 3 种方式中执行 Maven 命令&#xff1a; 使用 Run An…

RFID技术在工业自动化和生产流程优化方面的成功应用

您是否好奇于如何在工业场景中利用RFID技术实现更高效的操作和生产流程优化&#xff1f;ANDEAWELL作为国内知名的RFID工业识别设备供应商&#xff0c; 企业国产化替代的首选品牌&#xff0c;将带您深入探索RFID技术在工业领域的应用&#xff0c;揭示其优势和挑战&#xff0c;并…

召回率的概念

召回率 就是查出来的正确的数量除以所有正确的数量&#xff1b;准确率是用你查出来的正确的数量除以所有的数量&#xff08;包含正确和不正确的数量&#xff09;。 附上某位大佬的图&#xff1a;

激光盐密灰密测试仪

一、产品特点 KDYM-302L 激光盐密灰密测试仪采用检测技术将灰密测试与盐密测试合二为一&#xff0c;可同时检测出被测绝缘子的灰密度和盐密度&#xff0c;简化了绝缘子污秽检测的流程&#xff0c;非常适合在巡检现场和实验室使用。 二、主要特点 内置测试专用测试软件&#x…

WebP 转换工具

webp WebPcwebp 编码&#xff08;转换成 WebP&#xff09;dwebp 解码Android Studio 编码 WebP1、Convert to WebP...2、选项3、压缩4、直接运行即可 WebP Github&#xff1a;https://github.com/webmproject/WebPShop 中文教程&#xff1a;https://developers.google.com/sp…

对象存储服务MinIO简介

黑马程序员学习资料 MinIO简介 MinIO基于Apache License v2.0开源协议的对象存储服务&#xff0c;可以做为云存储的解决方案用来保存海量的图片&#xff0c;视频&#xff0c;文档。由于采用Golang实现&#xff0c;服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置简单&…

LFS搭建总结

该文档参考LFS官网 和 https://www.cnblogs.com/alphainf/p/16661308.html 下文中未提及的部分参考官方文档 环境准备 在Oracle VM VirtualBox中先创建一个20G的磁盘&#xff0c;安装bebian操作系统&#xff0c;此时该硬盘为sda&#xff0c;分了三个区&#xff0c;分别是Linu…

Selenium Python 教程第3章: 页面的相关操作

3、针对Web页面的相关操作 最基本的页面操作也许是使用WebDriver打开一个链接。 常规的方法是调用 get 方法: driver.get("http://www.python.org")WebDriver 将等待&#xff0c;直到页面完全加载完毕&#xff08;其实是等到 onload 方法执行完毕&#xff09;&…

VS报错 --- error LNK2019: 无法解析的外部符号

运行vs程序时候&#xff0c;一般会出现这个错误 &#xff1a; 1 error LNK2019: 无法解析的外部符号 _lws_create_context4&#xff0c;该符号在函数 "public: bool __thiscall WebsocketServerApp::startServer(char const *,int)" (?startServerWebsocketServe…

只是做笔记有必要入手苹果笔吗?好用又便宜的平替苹果笔

苹果原装电容笔和那种只具备倾斜压感的平替电容笔不一样&#xff0c;平替电容笔并没有具备重力压感。但是&#xff0c;如果你并不经常需要绘画的话&#xff0c;那么你也不必花费太多的金钱来购买一支价格如此贵的苹果电容笔&#xff0c;选择一款平替电容笔即可。在这里&#xf…