您的需求列表非常好,可以直接转化为类型。首先,让我们完全按照您所说的那样拼写出来。在 Swift 中,任何你会说“and”的地方都是一个结构体(或类或元组,但在本例中是一个结构体),而任何你会说“or”的地方都是一个枚举。
struct Model<Element> {
// 1. a String field
let string: String
// 2. either an Array<SomeElement>, or AnyRealmCollection<SomeObject>
enum Container {
case array([Element])
case realmCollection(AnyRealmCollection<Element>)
}
let elements: [Container]
// 3. a closure that acts upon the specific SomeElement or SomeObject.
let process: (Element) -> Void
}
编辑:实际上不可能在这里创建 .realmCollection 案例,因为 AnyRealmCollection 对 Element 提出了额外的要求。要解决这个问题,您必须围绕 AnyRealmCollection 构建一个额外的包装器,以消除该要求。 It's not hard, but it's tedious, 除非你真的需要区分 AnyRealmCollection 和 AnyCollection,否则我会避免这种情况。
“数组或领域集合”可能比您真正的意思更精确。我怀疑你的意思是“元素的集合”。如果这就是你的意思,那么我们可以更容易地说出来:
struct Model<Element> {
let string: String
let elements: AnyCollection<Element>
let process: (Element) -> Void
}
除了强制调用者将元素包装在AnyCollection 中,我还提供以下初始化:
init<C>(string: String, elements: C, process: @escaping (Element) -> Void)
where C: Collection, C.Element == Element {
self.string = string
self.elements = AnyCollection(elements)
self.process = process
}
通常,在 Swift 中避免使用元组,除非它用于非常简单和短暂的事情。 Swift 元组非常有限,制作一个结构太简单了,不能浪费时间在元组的所有限制上。
但是,这种类型不能放入具有不同元素的数组中。如果这是您使用 Model 的唯一方式,并且您无需将元素取出,则可以将其设为非泛型:
struct Model {
let string: String
let process: () -> Void
init<C: Collection>(_ string: String,
_ elements: C,
_ process: @escaping (C.Element) -> Void) {
self.string = string
self.process = { elements.forEach(process) }
}
}
let list = [Model("section1", AnyRealmCollection<Car>(), { _ in return }),
Model("section2", Array<Driver>(), { _ in return }),
Model("section3", AnyRealmCollection<Passenger>(), { _ in return })
]
如果有时您需要一个模型,有时您需要在不知道元素的情况下将其放入数组中,那么您可以构建一个类型橡皮擦:
struct AnyModel {
let string: String
let process: () -> Void
init<Element>(_ model: Model<Element>) {
self.string = model.string
self.process = { model.elements.forEach(model.process) }
}
}