Swift带关联类型的协议继承后声明变量仍报编译错误的原因?
问题原因
你在StartRouterProtocol声明中添加的where View == StartView约束,作用是限制所有遵守StartRouterProtocol的类型的关联类型必须为StartView,并没有消除协议本身的关联类型特征。
Swift中所有包含associatedtype或者用到Self约束的协议,本质上都不是完整的可直接使用的类型:只靠协议本身编译器无法确定其内存布局,所以默认不能直接用来声明变量、参数或者返回值类型,只能作为泛型约束使用。你添加的where子句只是缩小了关联类型的可选范围,没有改变协议带关联类型的本质,因此会触发编译报错。
常见解决方案
1. 作为泛型约束使用
如果使用场景允许在编译期确定具体的实现类型,直接把协议作为泛型约束即可:
// 泛型函数使用示例 func handleRouter<R: StartRouterProtocol>(router: R) { router.showSignInVC() } // 泛型类使用示例 class StartViewModel<R: StartRouterProtocol> { let router: R init(router: R) { self.router = router } }
2. 手动实现类型擦除(兼容所有Swift版本)
你可以封装类型擦除容器,隐藏遵守协议的具体类型的关联类型细节,对外暴露统一可用的类型:
class AnyStartRouter: StartRouterProtocol { private let _showTermsVC: () -> Void private let _showSignInVC: () -> Void private let _dismiss: (ViewController<StartView>?) -> Void init<R: StartRouterProtocol>(_ router: R) { _showTermsVC = router.showTermsVC _showSignInVC = router.showSignInVC _dismiss = router.dismiss } func showTermsVC() { _showTermsVC() } func showSignInVC() { _showSignInVC() } func dismiss(viewController: ViewController<StartView>?) { _dismiss(viewController) } } // 使用时直接声明为擦除后的类型即可 let router: AnyStartRouter = AnyStartRouter(具体的Router实现实例)
3. 使用Swift 5.7+新增语法
如果项目最低兼容版本为iOS 16+/macOS 13+,可以直接用any关键字声明存在类型,无需手动实现类型擦除:
let router: any StartRouterProtocol
如果变量的实现类型固定唯一,也可以用some关键字让编译器自动推断具体类型,性能优于any实现:
let router: some StartRouterProtocol = 具体的Router实现实例
内容的提问来源于stack exchange,提问作者Daniil Khrapovitskii
相关产品推荐
相关产品推荐

