how to say “same class” in a Swift generic

心不动则不痛 提交于 2020-01-22 22:50:11

问题


If a Swift generic type constraint is a protocol name, I can require that two types, constrained to that protocol, be the same type. For example:

protocol Flier {}
struct Bird : Flier {}
struct Insect: Flier {}
func flockTwoTogether<T:Flier>(f1:T, f2:T) {}

The function flockTwoTogether can be called with a Bird and a Bird or with an Insect and an Insect, but not with a Bird and an Insect. That is the limitation I want. So far, so good.

However, if I try the same thing with a class name, it doesn't work:

class Dog {}
class NoisyDog : Dog {}
class WellBehavedDog: Dog {}
func walkTwoTogether<T:Dog>(d1:T, d2:T) {}

The problem is that I can call walkTwoTogether with a WellBehavedDog and a NoisyDog. This is what I want to prevent.

There are really two questions here:

  • Is there a way to say that walkTwoTogether can't be called with a WellBehavedDog and a NoisyDog?

  • Is this a bug? I ask because if I can't use a generic to say this, it is hard to see why it is useful for a generic constraint to be a class name at all, since we could get the same result just with a normal function.


回答1:


Not an answer, per se, but some more data perhaps... The problem is when you call:

walkTwoTogether(NoisyDog(), WellBehavedDog())

Swift can just treat both instances as if they're instances of Dog (aka, upcast) — we need that so we can call methods meant for class A with subclasses of A. (I know you know this.)

Swift doesn't upcast to protocols, so the only way to do it is to specify a protocol for the subclasses that the superclass doesn't conform to:

protocol Walkable {}
extension NoisyDog : Walkable {}
extension WellBehavedDog: Walkable {}
func walkTwoTogether<T: Dog where T: Walkable>(d1:T, d2:T) { }

walkTwoTogether(NoisyDog(), WellBehavedDog())
// error: type 'Dog' does not conform to protocol 'Walkable'

The error message explicitly shows what is going on — the only way to call this version of walkToTogether is to upcast the subclass instances to Dog, but Dog doesn't conform to Walkable.




回答2:


I would say that this should be considered a bug since inout parameters change the type requirements as they should be:

func walkTwoTogether<T:Dog>(inout d1:T, d2:T) {

Now it has the expected behavior where you can only pass two values of the same type. (Tested in Swift 1.2 and Swift 2 beta 5)



来源:https://stackoverflow.com/questions/27323165/how-to-say-same-class-in-a-swift-generic

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!