非最终 class 中的方法必须 return `Self` 才能符合协议
Method in non-final class must return `Self` to conform to protocol
在协议扩展中 returning 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
会导致编译器出现段错误(sig 11)(这似乎是传达类型不匹配错误的有效方式)。
将 f()
的声明更改为 return P
,并在错误行上将 Self
替换为 P
,结果编译成功,但是会丢失类型精度(并且需要在每个调用站点强制向下转型,并详细记录 Self
要求)。
对于此问题是否有任何其他不丢失通用 return 类型的解决方法?
编辑:补充上下文不足的更多细节:P
是一个public协议,将由库公开,用于各种类型符合(并覆盖 g()
),因此在 NSData
中覆盖 f()
不是一个选项。最好不要将 f()
更改为协议扩展以外的其他内容,因为库在许多地方内部使用它。鉴于这两个选项,将 f()
的 return 类型更改为 P
是更好的选择。
更新
截至 Swift 4(可能是 3),以上代码按原样工作。
这对我有用....
protocol P {
static func foo()->Self
}
class C {
required init() {}
}
extension C: P {
static func foo() -> Self {
return self.init()
}
}
let c = C()
let c2 = C.foo()
print(c.dynamicType, c2.dynamicType) // C C
好的,我看到你注意到了,所以我进行了更新
protocol P {
static func foo()->Self
static func bar()->Self
}
extension P {
static func foo() -> Self { // Method 'f()' in non-final class 'NSData' must return `Self` to conform to protocol 'P'
return bar()
}
}
// the class C must be final ...
final class C {
}
// otherwise the compiler can not decide the type of Self in
extension C: P {
static func bar() -> Self {
return self.init()
}
}
let c = C()
let c2 = C.foo()
print(c.dynamicType, c2.dynamicType) // C C
对于NSData,如果你想做同样的,麻烦的是将NSData声明为final。
您需要在 NSData 扩展中覆盖 f()。
基本问题是(我认为)编译器在编译协议扩展中的 f
时不知道 Self
是什么,我认为它假定它必须是确切的类型在 class 中,它也在应用它。对于 NSData,情况可能并非如此,因为您可能有它的子class。
从 Swift 2.1 开始,我能够通过仅使结构(或 'final' 类)符合协议来避免给定的错误。目前,您可以将协议实现限制为引用类型 ("classes-only"),但我还没有看到对值类型的类似限制。
虽然在这种特殊情况下,我认为委托模式会适合。如果合适,您可以将 f 的默认实现移动到协议扩展中,并让子类实现覆盖委托 属性.
protocol P {
static var delegate : (() -> Self)?;
}
extension P {
static func f() -> Self {
// Use delegate if available, or use default implementation
}
}
extension NSData : P {
static var delegate : (() -> NSData)? = subImplementation;
func subImplementation() -> NSData {
// Some NSData-specific implementation
}
}
我也遇到了同样的问题,你解决了吗?
这是我处理特殊情况的另一种方法。
与其使用需要静态函数返回 Self
的协议,不如考虑定义一个需要初始化程序的协议。
像这样:
protocol SomeProtocol {
init(someParameter: Int)
}
不要忘记用 required
关键字标记初始化器实现。
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
}
}
希望这对您有所帮助。
在 Swift 3 或 4:
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self {
return g()
}
}
extension Data: P {
static func g() -> Data {
return self.init()
}
}
或者您可以将 class 替换为最终子class:
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self {
return g()
}
}
import Foundation
final class MyData: NSData {}
extension MyData: P {
static func g() -> Self {
return self.init()
}
}
如果 NSData 是那些 class 无法轻易被子class 的集群之一(您将看到带有 __CFRequireConcreteImplementation
的堆栈跟踪),您可能必须创建一个真正的 NSData 的最终 class 包装器,而不是使用 subclass.
您也可以使用关联类型来绕过它。
protocol P {
associatedtype Entity
static func f() -> Entity
static func g() -> Entity
}
extension P {
static func f() -> Entity {
return g()
}
}
extension Data: P {
static func g() -> Data {
return self.init()
}
}
您不需要在您的实现中指定 Entity
,因为编译器将从您的 return 类型推断它。
在协议扩展中 returning 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
会导致编译器出现段错误(sig 11)(这似乎是传达类型不匹配错误的有效方式)。
将 f()
的声明更改为 return P
,并在错误行上将 Self
替换为 P
,结果编译成功,但是会丢失类型精度(并且需要在每个调用站点强制向下转型,并详细记录 Self
要求)。
对于此问题是否有任何其他不丢失通用 return 类型的解决方法?
编辑:补充上下文不足的更多细节:P
是一个public协议,将由库公开,用于各种类型符合(并覆盖 g()
),因此在 NSData
中覆盖 f()
不是一个选项。最好不要将 f()
更改为协议扩展以外的其他内容,因为库在许多地方内部使用它。鉴于这两个选项,将 f()
的 return 类型更改为 P
是更好的选择。
更新
截至 Swift 4(可能是 3),以上代码按原样工作。
这对我有用....
protocol P {
static func foo()->Self
}
class C {
required init() {}
}
extension C: P {
static func foo() -> Self {
return self.init()
}
}
let c = C()
let c2 = C.foo()
print(c.dynamicType, c2.dynamicType) // C C
好的,我看到你注意到了,所以我进行了更新
protocol P {
static func foo()->Self
static func bar()->Self
}
extension P {
static func foo() -> Self { // Method 'f()' in non-final class 'NSData' must return `Self` to conform to protocol 'P'
return bar()
}
}
// the class C must be final ...
final class C {
}
// otherwise the compiler can not decide the type of Self in
extension C: P {
static func bar() -> Self {
return self.init()
}
}
let c = C()
let c2 = C.foo()
print(c.dynamicType, c2.dynamicType) // C C
对于NSData,如果你想做同样的,麻烦的是将NSData声明为final。
您需要在 NSData 扩展中覆盖 f()。
基本问题是(我认为)编译器在编译协议扩展中的 f
时不知道 Self
是什么,我认为它假定它必须是确切的类型在 class 中,它也在应用它。对于 NSData,情况可能并非如此,因为您可能有它的子class。
从 Swift 2.1 开始,我能够通过仅使结构(或 'final' 类)符合协议来避免给定的错误。目前,您可以将协议实现限制为引用类型 ("classes-only"),但我还没有看到对值类型的类似限制。
虽然在这种特殊情况下,我认为委托模式会适合。如果合适,您可以将 f 的默认实现移动到协议扩展中,并让子类实现覆盖委托 属性.
protocol P {
static var delegate : (() -> Self)?;
}
extension P {
static func f() -> Self {
// Use delegate if available, or use default implementation
}
}
extension NSData : P {
static var delegate : (() -> NSData)? = subImplementation;
func subImplementation() -> NSData {
// Some NSData-specific implementation
}
}
我也遇到了同样的问题,你解决了吗?
这是我处理特殊情况的另一种方法。
与其使用需要静态函数返回 Self
的协议,不如考虑定义一个需要初始化程序的协议。
像这样:
protocol SomeProtocol {
init(someParameter: Int)
}
不要忘记用 required
关键字标记初始化器实现。
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
}
}
希望这对您有所帮助。
在 Swift 3 或 4:
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self {
return g()
}
}
extension Data: P {
static func g() -> Data {
return self.init()
}
}
或者您可以将 class 替换为最终子class:
import Foundation
protocol P {
static func f() -> Self
static func g() -> Self
}
extension P {
static func f() -> Self {
return g()
}
}
import Foundation
final class MyData: NSData {}
extension MyData: P {
static func g() -> Self {
return self.init()
}
}
如果 NSData 是那些 class 无法轻易被子class 的集群之一(您将看到带有 __CFRequireConcreteImplementation
的堆栈跟踪),您可能必须创建一个真正的 NSData 的最终 class 包装器,而不是使用 subclass.
您也可以使用关联类型来绕过它。
protocol P {
associatedtype Entity
static func f() -> Entity
static func g() -> Entity
}
extension P {
static func f() -> Entity {
return g()
}
}
extension Data: P {
static func g() -> Data {
return self.init()
}
}
您不需要在您的实现中指定 Entity
,因为编译器将从您的 return 类型推断它。