我有一个模仿ForEach或List模式的通用SwiftUI视图,如下所示:
struct SwiftUIView<T: RandomAccessCollection, ElementView: View, ID: Hashable>: View {
@Binding var selection: T.Element
let keyPath: KeyPath<T.Element, ID>
let content: (T.Element) -> ElementView
var data: T
init(data: T, id: KeyPath<T.Element, ID>, selection: Binding<T.Element>, @ViewBuilder content: @escaping (T.Element) -> ElementView) {
...
}
var body: some View {
ForEach(data, id: keyPath) { element in
content(element)
}
}
}
,我正在尝试创建一些方便的初始化器来利用RandomAccessCollections的索引。
下面的初始化式将集合类型T映射到一些数组(T == Array<Value>.Indices
)的下标,编译时没有问题。
init<Value>(data: [Value], selection: Binding<Array<Value>.Index>, @ViewBuilder content: @escaping (Array<Value>.Index, Value) -> ElementView)
where T == Array<Value>.Indices, ID == Array<Value>.Index {
self.init(data: data.indices, id: .self, selection: selection) { index in
content(index, data[index])
}
}
一个类似的初始化器接受一个泛型形参C: RandomAccessCollection
并将T映射到C.Indices不编译:
init<C: RandomAccessCollection>(data: C, selection: Binding<C.Index>, @ViewBuilder content: @escaping (C.Index, C.Element) -> ElementView)
where T == C.Indices, ID == C.Index {
self.init(data: data.indices, id: .self, selection: selection) { index in
content(index, data[index])
}
}
注意,RandomAccessCollection的关联类型索引也符合RandomAccessCollection。
从表面上看,这应该可以工作,因为第二个初始化式中的C
类型应该作为第一个初始化式中的Array<Values>
的1:1替代品。
想知道我在这里可能遗漏了什么,或者如果编译器只是无法推断这里的所有一致性。
ForEach不使用这样的初始化式,而是显式地为Range<Int>
指定…但我认为你需要一些像(主要部分快照):
init(data: T, selection: Binding<T.Element>, @ViewBuilder content: @escaping (T.Element) -> ElementView)
where T.Element == ID {
在Xcode 13.3/iOS 15.4上测试
完整的发现、代码和演示在这里