您如何实现 return 协变 Selfs 的协议方法?

How do you implement protocol methods that return covariant Selfs?

错误:协议 'Protocol' 要求 'instance' 不能被非最终 class ('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()
    }
}

如其所说,您不能这样做,并且有充分的理由。你无法证明你会信守诺言。考虑一下:

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

所以根据您的协议 x 应该是 AnotherSubclass(即 Self)。但它实际上是 Subclass,这是完全不同的类型。除非 class 是 final,否则您无法解决这个悖论。这不是 Swift 限制。这种限制将存在于任何正确的类型系统中,因为它允许类型矛盾。

另一方面,您可以做的是保证 instance return 在所有子class 中(即超级class)有一些一致的类型.您可以使用关联类型执行此操作:

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 类型。 (它也恰好是随机的其他子class,这有点奇怪,但这就是代码所说的。)

顺便说一句,所有这些通常表明您在不应该使用 subclassing 的情况下使用。组合和协议可能会在 Swift 中更好地解决这个问题。问问自己是否有任何理由 Subclass 实际上需要成为 Class 的子 class。会不会是一个独立的类型,符合相同的协议?当您摆脱 subclasses 并专注于协议时,各种问题都会消失。


我一直在考虑这个问题,也许有一种方法可以得到你想要的东西。与其说所有子 class 都实现 instance,不如将 instance 作为扩展附加。如果你想 return 其他东西,你仍然可以覆盖它。

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 return类型错误”)。

如果您不想像这样对每个子 class 实际上 return Self return Self,这实际上是有意义的并且有效:

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

这意味着您的协议定义了一个类型别名,它必须是其自身的子class。以下代码将起作用:

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 被声明为 class 类型。但是你可以让它以某种方式像这样工作:

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

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