我发现swift超载+
与>
重叠的方式存在一些奇怪的差异:
protocol Value {
func get() -> Float
mutating func set(to:Float)
}
extension Float : Value {
func get() -> Float {
return self
}
mutating func set(to value:Float) {
self = value
}
}
func + (a:Value, b:Value) -> Float {
return a.get() + b.get()
}
func > (a:Value, b:Value) -> Bool {
return a.get() > b.get()
}
let a:Float = 1
let b:Float = 2
let c:Float = a + b //this works fine. Compiler calls Float + Float
let d = b > a //this causes infinite loop. Compiler recursively calls Value > Value
任何想法为什么swift编译器以不同的方式处理这些情况?
答案 0 :(得分:0)
区别在于标准库目前在+
上有Float
重载defined directly:
// TODO: These should not be necessary, since they're already provided by // <T: FloatingPoint>, but in practice they are currently needed to // disambiguate overloads. We should find a way to remove them, either by // tweaking the overload resolution rules, or by removing the other // definitions in the standard lib, or both. extension ${Self} { @_inlineable // FIXME(sil-serialize-all) @_transparent public static func + (lhs: ${Self}, rhs: ${Self}) -> ${Self} { var lhs = lhs lhs += rhs return lhs } // [...] }
(其中${Self}
将由Float
,Double
&amp; Float80
替换为gyb.py运行)
当涉及到重载解析时,(Float, Float) -> Float
的{{1}}重载会在应用+
个操作数时超过(Value, Value) -> Float
重载,因为后者需要它们从Float
转换为Float
。
但是Value
不会直接在其上定义Float
重载; it's instead defined as a top-level generic function超过>
个操作数:
FloatingPoint
当涉及到重载解析时,您的@_transparent
public func > <T : FloatingPoint>(lhs: T, rhs: T) -> Bool {
return rhs.isLess(than: lhs)
}
重载将胜过此泛型重载,因为重载解析有利于非泛型重载(请参阅正切in my answer here)。因此,你最终会反复出现。您可以通过使(Value, Value) -> Bool
泛型超过>
来解决此问题,但之后它将不再适用于异构<T : Value>(T, T) -> Bool
操作数。
假设您希望运算符适用于异构操作数,一个万无一失的解决方案是通过Value
符合>
来调用+
和Float
的调用。 {1}}和Numeric
使用嵌套的通用函数。这不能解决问题因为,Comparable
和(Value, Value) -> Float
都不能满足这些协议的(Value, Value) -> Bool
和+
要求。
>
(请注意,我们为func + (lhs: Value, rhs: Value) -> Float {
func add<T : Numeric>(_ lhs: T, _ rhs: T) -> T {
return lhs + rhs
}
return add(lhs.get(), rhs.get())
}
func > (lhs: Value, rhs: Value) -> Bool {
func greaterThan<T : Comparable>(_ lhs: T, _ rhs: T) -> Bool {
return lhs > rhs
}
return greaterThan(lhs.get(), rhs.get())
}
以及+
执行了此操作,因为可能会删除>
重载以支持通用重载,这会导致相同与+ (Float, Float) -> Float
)
另一种解决方案是避免完全转发>
和>
,而只需调用+
和Float
运算符上的isLess(than:)
方法,模仿stdlib实现:
+=
如果为func + (lhs: Value, rhs: Value) -> Float {
var lhsFloat = lhs.get()
lhsFloat += rhs.get()
return lhsFloat
}
func > (lhs: Value, rhs: Value) -> Bool {
return rhs.get().isLess(than: lhs.get())
}
实现了+=
的重载,则调用(inout Value, Value) -> Void
可能会有问题。