【问题标题】:Further constraining a generic function from a Swift Protocol进一步约束 Swift 协议的泛型函数
【发布时间】:2015-01-31 11:34:41
【问题描述】:

我有一个这样定义的 Swift 协议:

protocol MyProtocol {
    func genericMethod<T:MyProtocol>(param:T) -> ()
}

我可以像这样在基类中实现泛型方法:

class MyBaseClass : MyProtocol {
    func genericMethod<T where T:MyProtocol>(param:T) -> () {
        println("Performing generic method for type \(T.self)")
    }
}

class MySubClass : MyBaseClass {
    ...
}

到目前为止,一切都很好。我可以实现这个方法,它编译和运行都很好。

现在,我想做一些类似的事情,但在我的基类中,我想通过要求它符合诸如Comparable 之类的协议来进一步限制泛型方法的类型。我试试这个:

class MyBaseClass : MyProtocol {
    func genericMethod<T where T:MyProtocol, T:Comparable>(param:T) -> () {
        println("Performing generic method for type \(T.self)")
    }
}

一旦我在类型 T 上添加了这个附加约束,类 MyClass 将无法编译,因为它不再符合协议。

似乎在泛型类型上添加额外的约束不应该导致它停止符合协议。我错过了什么?在我看来,协议是说genericMethod 必须传递一个符合MyProtocol 类型的参数。当我在MyBaseClass 中实现它时——只是MyProtocol 的一种可能实现——我应该能够进一步限制该实现,方法是说参数 myst 符合Comparable 除了 MyProtocol

有没有办法像我在这里尝试的那样在基本实现中细化泛型类型?

【问题讨论】:

  • 我不明白你为什么感到惊讶。也许我遗漏了一些明显的东西,但在我看来,协议说:“采用我的人必须实现genericMethod,参数是他自己的类型。但T:MyBaseClass, T:Comparable 不是 MyBaseClass 自己的类型,因为 MyBaseClass 不采用 Comparable。因此,正如编译器所说,您违反了协议规定的合同。
  • 在协议中使用Self 引用只是演示问题的一种方式。如果我使用一个协议然后另一个协议,我会遇到同样的问题。我将更新问题以更清楚地说明为什么我对这种行为感到惊讶
  • 好的,感谢修改。好吧,编译器为什么不喜欢它的问题的答案是这些不匹配。协议要求func genericMethod&lt;T:MyProtocol&gt;(param:T) -&gt; ()func genericMethod&lt;T where T:MyProtocol, T:Comparable&gt;(param:T) -&gt; () 不同。您在一种心理上的正当脚注中说“一个是另一个的更受限制的版本”,但这对编译器无关紧要;关键是一个不是另一个。
  • 要查看此内容,请尝试更简单的变体:func genericMethod&lt;T&gt; (param:T) -&gt; ()func genericMethod&lt;T where T:Comparable&gt;(param:T) -&gt; ()。他们也不匹配,我认为原因更清楚。换句话说,您似乎认为一个泛型是另一个泛型的一种“子类”或“子集”。但这不是这些通用签名的工作方式。要么匹配,要么不匹配。
  • 我建议你复习一下里氏替换原则en.wikipedia.org/wiki/Liskov_substitution_principle

标签: swift generics


【解决方案1】:

在泛型类型上添加额外的约束应该导致它停止符合协议,因为协议应该保证一致性,并且不能保证与不是 Comparable 的子类型的一致性.如果您希望所有MyProtocol 对象都符合Comparable,那么您应该使其成为MyProtocol 定义的一部分。

protocol MyProtocol: Comparable {
    //...
}

我还没有尝试过,但如果您将 MyBaseClass 设为 Comparable 类型,它也可能会起作用。

【讨论】:

  • 我不希望所有 MyProtocol 对象都符合 Comparable。我希望MyBaseClass 的所有子类都继承genericFunction 方法,该方法是在知道这些特定子类也恰好符合Comparable 的情况下实现的。我将有其他 MyProtocol 基类以不同方式实现协议,而不必依赖于它们的子类符合 Comparable 的假设
  • 那你需要指定MyBaseClass符合Comparable。如果这样做,代码会编译吗?
【解决方案2】:

一种解决方案是另一种方式 - 将您的协议的泛型版本定义为最限制性的情况。这样编译:

protocol P {
    func genericMethod<T where T:P, T:Comparable>(param:T) -> ()
}

class C1 : P {
    func genericMethod<T> (param:T) -> () {} // compiles even though omits Comparable
    func test() {
        genericMethod(C1()) // compiles even though C1 is not a Comparable
    }
}

【讨论】:

  • 感觉像一个编译器错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多