在 Swift 中,我有一个类型上的泛型视图。我想要两个初始值设定项来限制我们可以用作泛型类型的内容。我也有这个视图的视图模型:
struct MyView<SomeType: Equatable>: View {
@State private var viewModel: ViewModel
init(someArray: [SomeType]) where SomeType == SomeTypeOption1 {
...
}
init(someArray: [SomeType]) where SomeType == SomeTypeOption2 {
...
}
}
(假设,基于围绕代码库的建模,我不想想要制定一个协议,
SomeTypeOption1
和SomeTypeOption2
符合并在我们传入的数组周围有一个包装器。)
现在在视图模型中,假设我们有一个对传递到视图中的
someArray
的引用。 我想根据SomeType
的类型重载一个函数。我将视图模型作为视图的扩展,因此通用类型得以保留。这是我尝试过的:
extension MyView {
@Observable class ViewModel {
var someArray: [SomeType]
...
func myFunc() where SomeType == SomeTypeOption1 {
someArray.append(SomeTypeOption1.init(...))
}
func myFunc() where SomeType == SomeTypeOption2 {
someArray.append(SomeTypeOption2.init(...))
}
}
}
但是,如果在我看来,我尝试调用
myFunc()
(比如在 Button
操作中),编译器会抱怨“没有与实例方法完全匹配”,所以我猜它遇到了麻烦弄清楚它可以使用这些函数(以及应该使用哪一个)。我本以为,因为我们在视图初始值设定项中有 where
子句,所以这不会是问题。
有人知道我该如何解决这个问题吗?
myFunc
的问题在于它需要可用于SomeType
泛型的所有可能值,因为编译无法推断出MyView
只能使用提供的两个值来实例化。
此外,该语言还没有提供将泛型参数限制为一组固定的具体类型的支持,即使提供了,您也需要一个抽象以便能够从视图中调用
myFunc()
型号。
正如其他人在评论中所说,最好的做法是重新设计您的代码。但是,如果您设置使用问题中描述的架构,一个快速的解决方法是声明一个不执行任何操作的非通用
myFunc
重载:
func myFunc() {
// this code is not reachable anyway, but we can add a
// crash that occurs only in Debug builds, to catch the impossible
assertionFailure("Should not reach here")
}
实际上,无法调用上述函数,因为拥有视图模型的视图只能使用具有相应重载的两种类型之一进行初始化。
但需要注意的是,需要注意好像
MyView
将支持新类型,那么 myFunc
也需要通过新的重载来增强。将不会有编译器支持来帮助您不要忘记更新两种类型(视图和视图模型)。