如何实现返回协变Selfs的协议方法?

时间:2015-10-07 17:59:55

标签: swift inheritance protocols

错误:协议'协议'要求'实例'不能被非最终类('Class')所满足,因为它在非参数非结果类型位置使用'Self'

protocol Protocol {
    var instance: Self {get}
}

class Class: Protocol {
    var instance: Class {return Subclass()}
}

class Subclass: Class {}

以下是我在C#中表达我想要的内容。 (据我所知,C#没有办法强制执行泛型参数“Self”实际上是我们从Swift知道的Self,但它的功能很好,因为文档可以让我做正确的事。)

interface Protocol<Self> where Self: Protocol<Self> {
    Self instance {get;}
}

class Class: Protocol<Class> {
    public Class instance {get {return new Subclass();}}
}

class Subclass: Class {}

......在未来的Swift版本中看起来如何:

protocol Protocol {
    typealias FinalSelf: Protocol where FinalSelf.FinalSelf == FinalSelf

    var instance: FinalSelf {get}
}

class Class: Protocol {
    var instance: Class {return Subclass()}
}

class Subclass: Class {}

我如何模仿与我的问题相关的部分:

protocol Protocol: ProtocolInstance {
    static var instance: ProtocolInstance {get}
}

protocol ProtocolInstance {}


class Class: Protocol {
    static var instance: ProtocolInstance {return Subclass()}
}

class Subclass: Class {}

而且,我认为这是我的代码的相关部分:

protocol Protocol {
    static var : Self? {get} // an existing instance? 
    static var : Self {get}  // a new instance

    func instanceFunc()
}

extension Protocol {
    static func staticFunc() {
        ( ?? ).instanceFunc()
    }
}

2 个答案:

答案 0 :(得分:7)

正如它所说,你不能这样做,而且有充分的理由。你不能证明你会信守诺言。考虑一下:

class AnotherSubclass: Class {}
let x = AnotherSubclass().instance

因此,根据您的协议(x),AnotherSubclass应为Self。但它实际上是Subclass,这是一种完全不同的类型。除非课程为final,否则您无法解决此悖论。这不是斯威夫特的限制。这种限制将存在于任何正确的类型系统中,因为它允许类型矛盾。

另一方面,你可以做的是承诺instance在所有子类(即超类)中返回一些一致的类型。您可以使用关联类型执行此操作:

protocol Protocol {
    typealias InstanceType
    var instance: InstanceType {get}
}

class Class: Protocol {
    var instance: Class {return Subclass()}
}

class Subclass: Class {}
class AnotherSubclass: Class {}
let x = AnotherSubclass().instance

现在x明确是Class类型。 (它也恰好是随机的其他子类,这有点奇怪,但这就是代码所说的。)

顺便说一下,所有这些通常都表明你在使用子类化的时候确实不应该这样做。组合和协议可能会更好地解决Swift中的这个问题。问问自己Subclass是否需要实际成为Class的子类。它是一个符合相同协议的独立类型吗?当你摆脱子类并专注于协议时,各种各样的问题都会消失。

我一直在考虑这个,并且可能有办法获得你想要的东西。不是说所有子类都实现instance,而是将instance作为扩展名附加。如果你想要返回别的东西,你仍然可以覆盖它。

protocol Protocol {
    init()
}

class Class: Protocol {
    required init() {}
    var instance: Class { return Subclass() }
}

extension Protocol {
    var instance: Self { return self.dynamicType.init() }
}

class Subclass: Class {}

这会避免继承问题(你不能以这种方式创建相同的“AnotherClass返回错误的类型”。

答案 1 :(得分:2)

如果您不想为每个子类实际返回Self,这实际上是有意义的并且有效:

protocol Protocol : class {
    typealias Sub : Self
    var instance: Sub {get}
}

这意味着您的协议定义了一个必须是其自身子类的类型。以下代码可以正常工作:

class Class: Protocol {
    var instance: Class {return Subclass()}
}

class Subclass: Class {}

Class().instance    // Returns SubClass()

但是上面的代码没有使用错误编译

error: inheritance from non-protocol, non-class type '`Self`'

我认为这是一个错误,因为Self被声明为类类型。但是你可以这样做:

protocol Protocol : class {
    typealias Sub : Class
    var instance: Sub {get}
}

但是你没有太多的协议本身,因为只有类本身应该符合它。