我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Swift 5.9 Macros 有哪些新更新

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Swift 5.9 Macros 有哪些新更新

在这里插入图片描述

前言

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

Macros(宏)

Macros(宏)在 Swift 中被引入,其中 SE-0382、SE-0389 和 SE-0397 结合起来,允许我们在编译时创建能够转换语法的代码。

在像 C++ 这样的语言中,宏是一种对代码进行预处理的方式,可以在代码被主编译器看到之前对其进行文本替换,从而生成那些你不想手动编写的代码。

Swift 的宏类似,但功能更强大,因此也更加复杂。还允许我们在编译前动态操作项目的 Swift 代码,从而在编译时注入额外的功能。

需要了解的关键信息

宏是安全的类型,不仅仅是简单的字符串替换,因此需要准确告诉宏它将处理的数据。

在构建阶段作为外部程序运行,并且不属于主应用目标。

宏被分解为多个较小的类型,例如 ExpressionMacro 用于生成单个表达式,AccessorMacro 用于添加 getter和setter,ConformanceMacro 用于使类型符合某个协议。

宏与解析后的源代码一起工作,可以查询代码的各个部分,例如正在操作的属性的名称、类型,或者结构体内部的各种属性。

宏在一个沙盒中工作,只能在给定的数据上操作。

最后一个部分最重要,Swift 的宏支持是基于 Apple 的 SwiftSyntax 库构建的,用于理解和操作源代码。必须将其作为宏的依赖项添加到项目中。

环境准备

了解完 Swift 宏的基本信息之后,终于我们可以进入到实战环节了,工欲善其事必先利其器,首先我们需要做好以下准备

  • macOS Ventura 13.3 以上操作系统
  • Xcode 15 以上,本文使用的版本是15.0 beta (15A5160n)
  • Swift 入门级语法(掌握 Hello World 的 4 种写法🙂)

然后我们需要初始化一个 Swift 宏开发工程。

直接打开 Xcode 15,File -> New -> Package

选择 Swift Macro 模版,然后给我们的工程起一个名字,我这里就叫做 “SwiftMacroKit”

打开工程,大功告成

这是一个 SPM 管理的工程,如果打开 Package 文件,我们可以看到它依赖了前面提到的 SwiftSyntax 库

dependencies: [        // Depend on the latest Swift 5.9 prerelease of SwiftSyntax        .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0-swift-5.9-DEVELOPMENT-SNAPSHOT-2023-04-25-b"),    ],

除此之外,工程其实还依赖了两个库, SwiftSyntaxBuilder 和 SwiftSyntaxMacros ,这三个库的职责分别是

  • SwiftSyntax:提供 Swift 语法树支持
  • SwiftSyntaxMacros:提供实现宏所需要的协议和类型
  • SwiftSyntaxBuilder:为展开新代码提供便捷的语法树创建 API

整个工程的源码主要有 4 个部分,截图示意如下

它们分别是

  • SwiftMacroKit:包含 Swift 宏的定义,注意这里不提供实现,但是会将定义与实现连接起来
  • SwiftMacroKitClient:一个测试工程(所以称为 Client),可以在 main 函数里测试 SwiftMacroKit 定义的宏
  • SwiftMacroKitMacros:宏的核心实现部分,最终打包成 macro 产物提供给其他模块使用,例如在 SwiftMacroKit 中引用
  • SwiftMacroKitTests:Swift 宏的测试模块,苹果官方推荐我们采用 TDD 的方式开发我们的宏,后面会讲到

创建一个宏

从一个简单的宏开始,以便可以看到它们的工作原理。

因为宏是在编译时运行的,所以我们可以创建一个小宏,返回应用程序构建的日期和时间——这对于调试诊断非常有帮助。

定义宏

首先,需要创建执行宏展开的代码,将 #buildDate 转换为类似于 “2023-06-05T18:00:00Z” 的字符串:

public struct BuildDateMacro: ExpressionMacro {    public static func expansion(        of node: some FreestandingMacroExpansionSyntax,        in context: some MacroExpansionContext    ) -> ExprSyntax {        let date = ISO8601DateFormatter().string(from: .now)        return "\"\(raw: date)\""    }}

重要提示:这段代码不应该出现在主应用目标中,我们不希望这段代码编译到最终的应用程序中,只需要在其中插入生成的日期字符串。

在同一个模块中,创建一个符CompilerPlugi协议的结构体,导出宏:

import SwiftCompilerPluginimport SwiftSyntaxMacros@mainstruct MyMacrosPlugin: CompilerPlugin {    let providingMacros: [Macro.Type] = [        BuildDateMacro.self    ]}

然后将其添加到 Package.swift 中的目标列表中:

.macro(  name: "MyMacrosPlugin",  dependencies: [    .product(name: "SwiftSyntax", package: "swift-syntax"),    .product(name: "SwiftSyntaxMacros", package: "swift-syntax"),    .product(name: "SwiftCompilerPlugin", package: "swift-syntax")  ])

这样就完成了在外部模块中创建宏的过程。剩下的代码可以放在任何想要使用宏的地方,比如主应用目标中。

这需要两个步骤,首先是定义宏是什么。在例子中,这是一个自由表达式宏,将返回一个字符串,存在于 MyMacrosPlugin 模块中,并且具有严格的名称 BuildDateMacro。因此,我们将这个定义添加到主目标中:

@freestanding(expression)macro buildDate() -> String =  #externalMacro(module: "MyMacrosPlugin", type: "BuildDateMacro")

实际使用宏

像下面这样:

print(#buildDate)

阅读这段代码时,最重要的是要明白主要的宏功能 —— BuildDateMacro 结构体内的所有代码——在构建时运行,并将其结果注入到调用点。因此,上面的小小 print() 调用将被重写为类似于以下代码:

print("2023-06-05T18:00:00Z")

这也意味着宏内部的代码可以非常复杂,可以以任何想要的方式构建日期,因为实际上完成的代码只看到了返回的字符串。

下面我们尝试一个稍微有用一些的宏,这次是创建一个成员属性宏。当应用于类等类型时,允许将属性应用到类中的每个成员。这在概念上与旧的 @objcMembers 属性相同,将 @objc 添加到类型中的每个属性。

例如,如果有一个可观察对象,它在每个属性上使用 @Published,可以编写一个简单的 @AllPublished 宏来完成这个工作。首先,编写宏本身:

public struct AllPublishedMacro: MemberAttributeMacro {    public static func expansion(        of node: AttributeSyntax,        attachedTo declaration: some DeclGroupSyntax,        providingAttributesFor member: some DeclSyntaxProtocol,        in context: some MacroExpansionContext    ) throws -> [AttributeSyntax] {        [AttributeSyntax(attributeName:SimpleTypeIdentifierSyntax(name: .identifier("Published")))]    }}

其次,在提供的宏列表中包含下面内容:

struct MyMacrosPlugin: CompilerPlugin {    let providingMacros: [Macro.Type] = [        BuildDateMacro.self,        AllPublishedMacro.self,    ]}

第三,在主应用目标中声明该宏,将其标记为附加的成员属性宏:

@attached(memberAttribute)macro AllPublished() = #externalMacro(module: "MyMacrosPlugin", type: "AllPublishedMacro")

现在可以将其用于注释可观察对象类:

@AllPublished class User: ObservableObject {    var username = "Taylor"    var age = 26}

宏可以接受参数来控制其行为,尽管在这里复杂性可能会大幅上升。例如,Swift 团队的 Doug Gregor 维护着一个小的 GitHub 存储库,其中包含一些示例宏,包括一个很强大的宏,在构建时检查硬编码的 URL 是否有效 —— 这样就不可能输入错误的 URL,因为构建过程将停止。

在应用程序目标中声明宏很简单,包括添加一个字符串参数:

@freestanding(expression) public macro URL(_ stringLiteral: String) -> URL = #externalMacro(module: "MyMacrosPlugin", type: "URLMacro")

使用宏也很简单:

let url = #URL("https://swift.org")print(url.absoluteString)

这将使 url 成为一个完整的 URL 实例,而不是一个可选值,因为在编译时检查了 URL 的正确性。

更难的是宏本身,需要读取传入的字符串 “https://swift.org” 并将其转换为 URL。Doug 的版本更加详细,但如果简化为最基本的形式,会是这样:

public struct URLMacro: ExpressionMacro {    public static func expansion(        of node: some FreestandingMacroExpansionSyntax,        in context: some MacroExpansionContext    ) -> ExprSyntax {        guard let argument = node.argumentList.first?.expression,              let segments = argument.as(StringLiteralExprSyntax.self)?.segments        else {            fatalError("#URL requires a static string literal")        }        guard let _ = URL(string: segments.description) else {            fatalError("Malformed url: \(argument)")        }        return "URL(string: \(argument))!"    }}

总结

首先,我们获得的 MacroExpansionContext 值具有一个非常有用的 makeUniqueName() 方法,它将生成一个新的变量名,确保不与当前上下文中的任何其他名称冲突。如果想要将新名称注入到最终的代码中,使用 makeUniqueName() 是一个明智的选择。

其次,宏的一个关注点是在遇到问题时如何调试代码——当无法轻松地逐步执行代码时,很难追踪发生了什么。在 SourceKit 中已经进行了一些工作,将宏扩展为重构操作,但是真正需要看到的是 Xcode 中的实际情况。

最后,宏所能实现的广泛转换可能意味着 Swift Evolution 本身在未来一两年内将发生变化,因为许多以前可能需要大量编译器支持和讨论的功能现在可以使用宏进行原型设计,甚至可能进行发布。

来源地址:https://blog.csdn.net/qq_36478920/article/details/131892330

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Swift 5.9 Macros 有哪些新更新

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Swift 5.9 Macros 有哪些新更新

文章目录 前言Macros(宏)需要了解的关键信息环境准备创建一个宏定义宏实际使用宏 总结 前言 虽然 Swift 6 已经在地平线上浮现,但 5.x 版本仍然有很多新功能-更简单的 if 和 switch 用法、宏
2023-08-16

Swift 5.9 有哪些新特性(二)

文章目录 前言Noncopyable 结构体和枚举结束变量绑定的生命周期makeStream() 方法添加 sleep(for:) 到 ClockDiscarding task groups总结 前言 虽然 Swift
2023-08-17

Swift 5.9 有哪些新特性(一)

文章目录 前言if 和 switch 表达式Value 和 Type 参数包 前言 虽然 Swift 6 已经在地平线上浮现,但 5.x 版本仍然有很多新功能-更简单的 if 和 switch 用法、宏、非可复制类型、自定
2023-08-16

Ubuntu 16.04 LTS有哪些更新

本篇内容介绍了“Ubuntu 16.04 LTS有哪些更新”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Canonical刚刚正式发布了Ub
2023-06-13

win1019033更新的内容有哪些

今天小编给大家分享一下win1019033更新的内容有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。win1019033
2023-07-02

pgsql的更新规则有哪些

UPDATE语句:使用UPDATE语句来更新表中的数据,指定要更新的列和新的值。约束:可以通过定义约束(如主键、唯一约束、外键约束等)来限制更新操作,保证数据的完整性。触发器:可以在更新数据时触发一个触发器,执行一系列的操作。视图:更新视图
pgsql的更新规则有哪些
2024-03-01

react更新state方法有哪些

react更新state方法有:1、通过key变化子组件,代码如“<Children key={this.state.key} a={this.state.a} b={this.state.b} />”;2、利用ref父组件调用子组件函数;3、通过父级给子级传数据,子级只负责渲染。
2022-11-22

Nessus更新到8.5.0有哪些变化

这期内容当中小编将会给大家带来有关Nessus更新到8.5.0有哪些变化,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Nessus更新到8.5.0此次更新,主要涉及以下变化:(1)Nessus的用户注册和
2023-06-05

Nessus更新到8.6.0有哪些变化

这期内容当中小编将会给大家带来有关Nessus更新到8.6.0有哪些变化,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Nessus更新到8.6.0此次更新,变化主要有以下几点:(1)加强过期提醒、购买链接
2023-06-05

MySQL update更新的方法有哪些

MySQL中更新数据的方法有以下几种:使用UPDATE语句更新数据:通过UPDATE语句可以更新表中的数据。语法如下:UPDATE 表名 SET 列名1=值1, 列名2=值2, ... WHERE 条件;示例:UPDATE studen
MySQL update更新的方法有哪些
2024-02-29

windows KB4499162更新的内容有哪些

本篇内容介绍了“windows KB4499162更新的内容有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!KB4499162更新内容有
2023-07-01

win10关闭更新的方法有哪些

  win10系统是目前的主流系统,现在很多电脑都预装的win10系统,深受电脑用户的喜爱,但是win10系统有一个令人非常头疼的问题,很多用户都不知道win10关闭自动更新,下面,小编就把win10关闭自动更新的方法教给大家。  win1
2023-07-10

windows更新失败的原因有哪些

Windows 更新失败的原因有很多,以下是一些常见的原因:1. 网络连接问题:在下载和安装更新过程中,如果网络连接不稳定或中断,可能导致更新失败。2. 存储空间不足:Windows 更新需要足够的硬盘空间来下载和安装更新,如果磁盘空间不足
2023-09-11

bios更新对电脑有哪些影响

这篇文章主要介绍“bios更新对电脑有哪些影响”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“bios更新对电脑有哪些影响”文章能帮助大家解决问题。bios更新对电脑的影
2023-03-02

Visual Studio更新到16.3.8有哪些优化

Visual Studio更新到16.3.8有哪些优化,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。Visual Studio更新到16.3.8此次更新包括以下
2023-06-05

win11更新失败的原因有哪些

Win11更新失败的原因可能有以下几种:1. 硬件不符合要求:Win11有一些硬件要求,如较新的处理器、4GB以上的内存、64GB以上的存储空间等,如果你的设备不符合这些要求,更新可能会失败。2. 硬件驱动不兼容:有些老旧的硬件设备可能没有
2023-08-22

docker更新镜像的方法有哪些

Docker 更新镜像的方法有以下几种:1. 通过 `docker pull` 命令拉取最新版本的镜像。可以使用 `docker pull :` 命令拉取指定标签的镜像,例如 `docker pull ubuntu:latest`。2. 使
2023-08-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录