我有两个函数,每个函数都有相同的名称。参数几乎相同,但一个函数引用特定类,而另一个函数引用该特定类的基类。当调用带有基类参数的第二个函数时,Swift 会对其进行编译以创建无限递归。它应该编译它以根据参数类型调用“正确”的函数(第一个)。在此代码中,请注意
Element
是 Spline
的基类。当 Spline 对象作为元素参数传递时,由于递归,对第二个底部函数的调用以崩溃结束:
func getArea( of spline: Spline, areaType: AreaType, scale: Scale ) -> Rect {
let area = spline.getArea( areaType: areaType )
if !area.isEmpty {
let renderArea = scale.toDestination( from: area )
if areaType == .selection {
return renderArea.inflated( by: scale.toDestinationUnits( from: StaticDrawingParameters.controlKnobRadius ) * 2.0 )
} else {
return renderArea
}
//return renderArea
}
return area
}
func getArea( of element: Element, areaType: AreaType, scale: Scale ) -> Rect? {
if let spline = element as? Spline {
return getArea( of: spline, areaType: areaType, scale: scale )
}
return nil
}
当使用恰好是
Element
的 Spline
引用调用第二个函数时,它会正确地将 Element
转换为 Spline
引用(根据调试器),然后调用它所在的 getArea() 函数已经存在。它不使用其他 getArea() 函数,即使它有一个参数是 Spline
而不是 Element
。
我正在尝试找出我的错误或确定编译器无法正确处理此问题。
代码是这样设计的,因为我使用了需要处理的各种类型的
Element
对象的数组(为了清楚起见,我删除了其中的一些代码)。每个派生类型都派生自 Element
,并且每个派生类型的面积计算方式都不同。面积计算还涉及使用有关输出设备的信息(屏幕、打印机、某种奇怪的文本格式的文件等),因此数据对象本身不知道如何执行此操作。否则,这些将是各个元素类中的成员函数。
代码中是否有错误,或者我认为编译应该根据参数类型正确选择要调用的函数?
我将更改参数名称来解决此问题,但如果是我犯的错误导致了此问题,我宁愿修复它。
首先,请不要这样做。如果您要使用继承,请使用继承:
class Element {
func area(type: AreaType, scale: Scale) -> Rect? { nil }
}
class Spline: Element {
override func area(type: AreaType, scale: Scale) -> Rect { ... }
}
但是您的解决方案不起作用的原因是它们实际上并不那么相似。它们有不同的返回类型。所以,鉴于这一行:
return getArea( of: spline, areaType: areaType, scale: scale )
编译器此时需要一个
Rect?
。它寻找一个 getArea(of:areaType:scale:)
,返回一个 Rect?
,并且只有一个。您希望它也对返回Rect
的方法执行可选升级,但它并没有这样做。它已经找到了一个可以准确返回它想要的内容的方法。
您可以通过使签名实际匹配并返回样条线版本来解决此问题
Rect?
。但更好的解决方案是直接使用继承。那么可选促销就不含糊了。请注意,在我上面的继承中, Spline.area
返回一个非可选值。由于override
,促销变得明确。
(也就是说,我确实建议避免在 Swift 中进行类继承,并且通常更喜欢使用协议和结构来处理此类事情。但是继承确实有效。)