给定一个外部类型:
struct Factory<T> {
public func callAsFunction() -> T {
registration.resolve(with: ())
}
}
我把它扩展成这样:
extension Factory {
func callAsFunction<U>() -> U {
guard let result = callAsFunction() as? U else {
preconditionFailure("Found '\(T.self)', but unable to convert it to '\(U.self)'")
}
return result
}
}
例如,你可以给出:
protocol P {}
struct MockP: P {}
extension Container {
var mockP: Factory<any P> {
Factory<any P>(self) { MockP() }
}
}
let mock: any P = Container.shared.mockP() // <- Does not check compile time that mockP implements P
我想限制它,这样你就不能例如:
protocol P { }
struct Valid: P { }
protocol Invalid { }
let result: any P = Container.shared.mockP() // <- This is a cast from P to Valid
let invalid: any Invalid = Container.shared.mockP() // <- Error: MockP does not conform to Invalid
但我不希望像现在这样出现运行时错误,而是编译器错误,因为检查Invalid不符合P
。
有什么办法可以做到这一点吗?
编辑:
我正在寻找类似于func callAsFunction<U: T>() -> U
的东西,但实际上是有效的。
2条答案
按热度按时间mwyxok5s1#
在Swift中,不可能使用扩展来实现编译时检查您正在寻找的限制类型。您提供的扩展在运行时运行,并依赖于类型转换,而类型转换只能在运行时检查。
要强制泛型类型
T
在使用callAsFunction
方法时必须符合P
的约束,您可以尝试以下操作(创建func而不是extent):我创建了两个独立的
callAsFunction
方法:*第一个只有当泛型类型
U
符合P
协议时才可用,以确保在编译时满足约束。*第二个
callAsFunction
方法是一个回退方法,将在类型U
不符合P
时使用如果你想把泛型类型
U
修改成和T
一样,你可以修改代码如下:*通过此修改,可以实现编译时检查,确保调用
callAsFunction
方法时泛型类型U
匹配类型T
。我希望它能帮上忙。如果有,请留下您的意见!!^^
2cmtqfgy2#
你所描述的是行不通的。特别地,这个函数正在做出承诺:
它声称调用者可以传递任何类型U,并且该函数将返回U的示例或永远不会返回。(“永不返回”意味着无限循环或崩溃。从技术上讲,它与返回
Never
类型的值相同,在本例中,您可以将其视为每种类型的子类型。对于
any Invalid
,编译器不会给出错误,因为它是U类型,而您编写了一个返回该类型的函数。在这里给出的情况下,答案是删除扩展,并在构造过程中捕获错误。我不得不猜测Factory是什么样子的(也许问题是它过于聪明,充满了Any,这是一个坏主意,但假设它看起来是这样的):
然后是基本的东西:
使用它:
如果你让MockP不符合P,那么编译错误会发生在
mockP
的定义上。也就是说,我敢肯定,工厂并不完全这样工作,还有更多的问题。您需要编辑您的问题以包括其他内容。但是你的扩展没有任何用处(它只能在不需要的时候工作)。所以我会回到你真正的问题是什么。