Swift带默认值初始化器调用歧义,求非修改式解决方法
解决Swift初始化器调用歧义的实用方法
我写的类里有两个结构相近的初始化器:
public init( contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6), midToLeftSpacing: CGFloat = 0, rightToMidSpacing: CGFloat = 0 ) public init( contentInsets: MyInsets = .init(vertical: .level0, horizontal: .level6), midToLeftSpacing: MyInsetLevel = .level0, rightToMidSpacing: MyInsetLevel = .level0 )
当我用下面的方式调用时,编译器没法判断该选哪一个,直接报 Ambiguous use of 'init' 错误:
YourClassName( vertical: .level0, left: .level22, right: .level0 )
虽然改初始化器或者加带默认值的参数能搞定,但总觉得不太合理,有没有不用改原代码就能指定调用哪个初始化器的办法?
1. 显式声明参数类型
直接给参数加上类型标注,让编译器一眼锁定目标初始化器:
调用接受CGFloat的版本
YourClassName( contentInsets: MyInsets(vertical: .level0, horizontal: .level22), midToLeftSpacing: CGFloat(0), rightToMidSpacing: CGFloat(0) )
调用接受MyInsetLevel的版本
YourClassName( contentInsets: MyInsets(vertical: .level0, horizontal: .level22), midToLeftSpacing: MyInsetLevel.level0, rightToMidSpacing: MyInsetLevel.level0 )
2. 用临时变量辅助类型推断
如果不想写全类型名,可以先定义对应类型的临时变量,再传入参数:
let targetSpacing: MyInsetLevel = .level0 YourClassName( contentInsets: MyInsets(vertical: .level0, horizontal: .level22), midToLeftSpacing: targetSpacing, rightToMidSpacing: targetSpacing )
或者直接在参数里做类型转换,更简洁:
YourClassName( contentInsets: MyInsets(vertical: .level0, horizontal: .level22), midToLeftSpacing: .level0 as MyInsetLevel, rightToMidSpacing: .level0 as MyInsetLevel )
3. 利用初始化器引用明确指定
如果需要把初始化器作为参数传递,或者想更清晰地指定版本,可以用初始化器引用的方式:
// 绑定接受CGFloat的初始化器 let cgFloatInitializer: (MyInsets, CGFloat, CGFloat) -> YourClassName = YourClassName.init let instance1 = cgFloatInitializer(MyInsets(vertical: .level0, horizontal: .level22), 0, 0) // 绑定接受MyInsetLevel的初始化器 let levelInitializer: (MyInsets, MyInsetLevel, MyInsetLevel) -> YourClassName = YourClassName.init let instance2 = levelInitializer(MyInsets(vertical: .level0, horizontal: .level22), .level0, .level0)
这些方法都不需要修改原有的初始化器代码,通过显式指定参数类型或初始化器引用,就能让编译器明确你要调用的版本,完美解决歧义问题。
内容的提问来源于stack exchange,提问作者Evgeniy Kleban
相关产品推荐
相关产品推荐

