SwiftUI带' where '约束的视图方便初始化器



我有一个模仿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上测试

完整的发现、代码和演示在这里

最新更新