这是一个正在进行中的项目,主要因为我感觉它仍然可以改进,并且尚未完全测试其用例。
一个 Swift 包,以及一种创建类型组的方法,以便可以使用编译时检查来寻址它们。它可以用于类型擦除,在这种情况下,您始终可以返回到原始类型,因为您始终知道其特定类型的所有可能类型。如果添加了新类型,编译器会通知您是否有任何 switch
没有处理这个新的子类型。它通过 Swift 宏和一些协议来实现所有这些。
import TypeFamily
protocol ArtistGroup: TypeFamilyChild, Equatable {
var memberCount: Int { get }
}
@TypeFamily(.keyPathed) @dynamicMemberLookup
enum MusicGroup: Equatable {
typealias TypeChild = ArtistGroup
@TypeFamilyChild
struct Orchestra: TypeChild {
let director: String
let memberCount: Int
}
@TypeFamilyChild("popArtist")
struct PopProducingTeam: TypeChild {
let vocalist: String
let presentedAsSolo: Bool
let teamMembersCount: Int
var memberCount: Int {
presentedAsSolo ? 1 : teamMembersCount + 1
}
}
}
let presentations: [MusicGroup] = [
.orchestra(.init(director: "A", memberCount: 20)),
.popArtist(.init(vocalist: "B", presentedAsSolo: true, teamMembersCount: 20)),
]
for presentation in presentations {
print("Members in main scenario: \(presentation.memberCount)")
switch presentation {
case .orchestra(let val):
print("Everyone besides \(val.director) need to enter stage in advance")
case .popArtist(let val):
print("\(val.vocalist) needs help entering stage at the start of the show")
}
let value = presentation.childValue
print(presentation == .wrapping(value)) // true
}
这是一个 Swift Package。如果您使用的是 Xcode 项目/工作区,请检查项目的 Package Dependencies,或者如果您正在编写 Swift Package,请检查您的 Package.swift
文件。 Xcode 将要求您启用 TypeAlias 的宏扩展。 这使得编译器生成代码,因此请启用它。 此外,某些版本的 Xcode 似乎需要重新启动(完全关闭 Xcode,再次打开 Xcode)才能识别宏。
首先,声明父类型。 这将始终是一个 enum
,并在其开头具有宏 @TypeFamily
。
@TypeFamily
enum ExampleParent {
}
编译器会要求您为子类型指定一个在它们之间共享的类型,在类型别名 TypeChild
下指定
protocol ExampleProtocol {
var aMethodThatAllChilrenHave: Bool { get }
}
@TypeFamily
enum ExampleParent {
typealias TypeChild = ExampleProtocol
}
现在您可以添加任何您需要的子类型。 子类型需要声明在父类型内部,以继承/遵守 TypeChild
协议,并具有宏 @TypeFamilyChild
。
// ...
@TypeFamilyChild
struct ExampleChild: TypeChild {
let aMethodThatAllChilrenHave: Bool
let somethingOnlyThisChildHas: Int
}
// ...
... 就是这样!
enum
case。case exampleChild(ExampleChild)
@TypeFamilyChild
参数中@TypeFamilyChild("customEnumCaseName")
// This generates `customEnumCaseName(ExampleChild)`
any TypeChild
var childValue: any TypeChild
// ...
let exampleParent = ExampleParent.exampleChild(.init(/* ... */))
print(exampleParent.childValue.aMethodThatAllChilrenHave)
.keyPathed
与 @dynamicMemberLookup
一起指定给 @TypeFamily
,以便能够直接从其父类型使用子属性@TypeFamily(.keyPathed) @dynamicMemberLookup
enum ExampleParent {
// ...
let exampleParent = ExampleParent.exampleChild(.init(/* ... */))
print(exampleParent.aMethodThatAllChilrenHave)
let exampleParent = ExampleParent.exampleChild(.init(/* ... */))
let child = exampleParent.childValue
let anotherParent = ExampleParent.wrapping(child) // Same as `exampleParent`