一个 Swift 宏,用于通过修改属性来创建结构体的内联副本。
语法类似于 Kotlin 数据类的 copy 函数:https://kotlinlang.org/docs/data-classes.html#copying
将 @Copyable
宏应用于结构体
@Copyable
struct Person {
let name: String
var age: Int
}
它将为每个存储属性和常量添加一个 copy 函数
struct Person {
let name: String
var age: Int
/// Returns a copy of the caller whose value for `name` is different.
func copy(name: String) -> Self {
.init(name: name, age: age)
}
/// Returns a copy of the caller whose value for `age` is different.
func copy(age: Int) -> Self {
.init(name: name, age: age)
}
}
要创建结构体的副本并修改多个属性,您可以像这样链式调用 copy
Person(name: "Walter White", age: 50).copy(age: 52).copy(name: "Heisenberg")
这与 Kotlin 的 copy
版本不同,后者允许在单个调用中传递多个参数。
在 Swift 中不可能像那样实现,因为无法为参数设置默认值,而这些默认值是指结构体(或类)的属性的当前值。
我们也不能使用 nil 作为旧值/当前值的标记,因为 nil 可能是一个有效的新值,我们希望在创建副本时将属性设置为该值。
可能还有我不知道的方法来实现它。所以如果你知道怎么做,请告诉我。
在 2.1.0 版本中,引入了单独的宏 CopyableCombi,它会生成具有所有参数组合的 copy 函数。这种解决方案的缺点是生成的函数数量会很快变得很大,但它提供了一个更类似于 Kotlin copy 函数的 API。
将为结构体的每个存储属性(var
)和每个常量(let
)生成一个 copy 函数。
该宏通过检查计算属性是否具有 get
或 set
访问器来识别它们。
此宏仅适用于结构体。
对于枚举没有意义,因为枚举不能有存储属性。
类和 actor 具有引用语义,我不希望此库为引用类型提供 copy 函数。我只想通过修改的属性来增强结构体的自然复制能力。
当您尝试将其应用于结构体以外的任何内容时,此宏会发出诊断消息。
生成的 copy 函数通过调用合成的默认初始化器来生成副本。
因此,如果您提供自定义初始化器,则不会合成默认初始化器,并且 copy 函数将无法工作。
如果您在扩展中定义自定义初始化器,您仍然可以拥有合成的默认初始化器。
您不能将此宏应用于结构体的扩展。
这似乎是宏系统的局限性。
如果您知道如何实现它,请告诉我 :)
宏是 Swift 5.9 的一项新语言功能,它仅适用于 Xcode 15 及更高版本。
将 url https://github.com/WilhelmOks/ModifiedCopyMacro.git
作为 Swift Package 添加到您的项目。
出现提示时,选择要添加到目标的 Package Product ModifiedCopy
(类型:库)。
进行 clean build。
在您要附加 @Copyable
宏的文件中 import ModifiedCopy
。