子类型的Swift协议一致性要求

时间:2018-01-25 00:15:07

标签: swift protocols standards-compliance subtype

(如果有人可以提出更好的标题,请做)

以下代码无法使用错误Type 'ObserverClass' does not conform to protocol 'Observer'进行编译,并且编译器通过声明var object: ObservedObject来建议修复。

class ObservedObject {}
class ObservedObjectSubclass: ObservedObject {}

protocol Observer {
    var object: ObservedObject { get }
}

class ObserverClass: Observer { // Type 'ObserverClass' does not conform to protocol 'Observer'

    // suggested:
    // var object: ObservedObject

    var object: ObservedObjectSubclass = ObservedObjectSubclass()
}

我看到它的方式 - ObservedObjectSubclass ObservedObject,因此保证object属性的类型为ObservedObject协议。

(如果使用协议一致性而不是子类化,则同样如此)

protocol ObservedObjectProtocol {}
protocol Observer {
    var object: ObservedObjectProtocol { get }
}

class ObservedObject: ObservedObjectProtocol {}

class ObserverClass: Observer { // same error
    var object: ObservedObject = ObservedObject()
}

为什么编译器不开心?它是当前的限制,还是编译器实际上是正确的,并且存在一些逻辑约束?

1 个答案:

答案 0 :(得分:3)

当您在协议中定义变量并为其分配类型时,这将是一个具体类型,因此在符合协议时您无法将其更改为该类型的子类。在符合类中声明的变量的类型必须与协议中声明的类型相同,它不能是协变(与继承相关)类型。

您可以通过为associatedType协议创建Observer来修复第二个错误,该协议继承自ObserverObject,然后您可以将object定义为与ObserverClass相同的类型你的相关类型。然后,您可以让object拥有ObservedObjectSubclass类型的媒体class ObservedObject {} class ObservedObjectSubclass: ObservedObject {} protocol Observer { associatedtype ObjectSubclass: ObservedObject var object:ObjectSubclass { get } } class ObserverClass: Observer { var object = ObservedObjectSubclass() }

fun getPage() { val page: Page = WebClient().getPage("http://htmlunit.sourceforge.net") }