当在协议扩展中实现返回Self
的静态协议函数时,在扩展中实现函数时会出现错误(所示的最小简化方案没有上下文):
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self { // Method 'f()' in non-final class 'NSData' must return `Self` to conform to protocol 'P'
return g()
}
}
extension NSData: P {
static func g() -> Self {
return self.init()
}
}
在发生错误的行上用P
替换Self
会导致编译器segfault(sig 11)(这似乎是传达类型不匹配错误的有效方式)。
将f()
的声明更改为返回P
,以及在错误行中将Self
替换为P
,可以成功编译,但会丢失类型精度(并且需要在每个调用站点强制向下转换,并详细记录Self
要求)。
对于此问题,是否有其他不会丢失泛型返回类型的解决方法?
EDIT:补充缺少上下文的详细信息:P
是一个公共协议,它将由库公开,以使各种类型符合(并覆盖g()
),因此在NSData
中覆盖f()
不是一个选项。最好不必将f()
更改为协议扩展以外的内容,因为库在内部的很多地方都使用它。给定这两个选项,将f()
的返回类型更改为P
是更好的选择。
更新
从Swift 4(可能是3)开始,以上代码按原样工作。
6条答案
按热度按时间u4vypkhs1#
在Swift 3或4中:
或者,您可以使用最终子类替换您的类:
如果NSData是那些不能轻易子类化的类簇之一(您将看到一个带有
__CFRequireConcreteImplementation
的stacktrace),您可能必须为真实的的NSData创建一个最终的类 Package 器,而不是使用子类。qij5mzcb2#
您需要在NSData扩展中覆盖f()。
基本的问题是(我认为)当编译器在协议扩展中编译
f
时,它不知道Self
是什么,并且我认为它假设它必须是它所应用的类的确切类型。对于NSData,情况可能不是这样,因为你可能有它的子类。yqhsw0fo3#
这对我很有效。
好吧,我看到你笔记了,所以我做了更新
对于NSData,如果您想做同样的事情,麻烦的是将NSData声明为final。
bksxznpy4#
从Swift 2.1开始,我可以通过只让结构体(或'final'类)符合协议来避免这个错误。目前,你可以限制协议实现为引用类型(“classes-only”),但我还没有看到对值类型的类似限制。
在这个特殊的例子中,我认为委托模式是合适的。如果合适的话,你可以把f的默认实现移到一个协议扩展中,并让子类实现覆盖一个委托属性。
ttp71kqs5#
您也可以使用相关的型别来解决这个问题。
您不需要在实现中指定
Entity
,因为编译器将从您的返回类型推断它。v09wglhw6#
我也有同样的问题,你发现了吗?
这是我提出的另一种处理特殊情况的方法。也许你可以考虑定义一个需要初始化程序的协议,而不是使用需要返回
Self
的静态函数的协议。就像这样:
不要忘记用关键字
required
标记初始化器实现。希望这能有所帮助。