2015-12-15 37 views
15

当在协议扩展中实现返回Self的静态协议函数时,扩展中的函数实现时会出现错误(最小简化方案显示为无上下文):非最终类中的方法必须返回`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() 
    } 
} 

Self更换用P上发生错误的行使编译器段错误(SIG 11)(这似乎输送类型不匹配错误的有效的方式)。

改变的f()声明返回P,以及对错误行与P更换Self,导致编译成功,但失去式精密(并要求部队在每次调用点向下转型,加上记录在Self要求详情)。

是否有任何其他解决此问题的方法不会失去通用返回类型?

EDIT:进一步的细节,以补偿缺少的上下文:P是一个公共协议,它由库被暴露,用于各种类型的,以符合(并重写g()),f()NSData所以压倒一切的不是一个选项。最好不要将f()更改为协议扩展以外的内容,因为它在很多地方被库内部使用。鉴于这两种选择,将f()的返回类型更改为P是更好的选择。

+2

“导致编译器出现segfault(sig 11)(这似乎是传达类型不匹配错误的有效方式)”。请确保您向Apple报告。 – JeremyP

回答

1

这对我的作品....

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。

+0

这对我有帮助吗?我提到我提供的例子是简化的 - 我不能只删除真正的函数'g'。 – Greg

1

您需要覆盖NSData扩展中的f()。

基本的问题是(我认为)编译器不知道Self是什么时候编译f在协议扩展中,我认为它认为它必须是它正在应用它的类的确切类型。对于NSData,情况可能并非如此,因为你可能有它的一个子类。

+0

对不起,如果我不清楚;不幸的是,在'NSData'中覆盖'f'不是一个选项,因为这只是许多类的一个例子,它们将符合我的控制。我已经用更多的细节更新了这个问题。 似乎我必须等待Swift 3.0才能成为可能而没有解决方法... – Greg

1

从Swift 2.1开始,我只能通过使结构(或'最终'类)符合协议来避免给定的错误。目前,您可以将协议实现限制为引用类型(“仅限类”),但我没有看到类似的值类型限制。

在这个特殊情况下,我会说委托模式适合。如果合适,您可以将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 
    } 
} 
0

我有同样的问题,你知道吗?

这是我出来处理特定情况的另一种方式。 而不是使用需要静态函数返回Self的协议,也许你可以考虑定义一个初始化器所需的协议。

像这样:

protocol SomeProtocol { 
    init(someParameter: Int) 
} 

不要忘记,以纪念与required关键字初始化实施。

class SomeClass: SomeProtocol { 
    required init(someParameter: Int) { 

    } 
} 

希望这可以帮助。

3

在斯威夫特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() 
    } 
} 

或者你可以用一个最后的子类替换类:

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的是,不能轻易地被继承的类集群之一(你会看到一个带有__CFRequireConcreteImplementation的栈跟踪),你可能不得不为真实的NSData创建一个最终的类包装,而不是使用子类。

+0

我解决了我的问题,正如你所说的那样让我的课程成为'final'。谢谢! –

+0

你确定你已经测试过吗?但它在Swift 3中不起作用。它仍然抱怨'非最终类'Data'中的方法'g()'必须返回'Self'以符合协议'P'。' – ozgur

+0

@OzgurVatansever我不记得了,但可能我做了。我没有再使用Swift 3,但是我编辑了包含Sw​​ift 4中编译的完整示例。 – Jano

相关问题