非最终 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 类型推断它。