问题
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
walkTwoTogethercan'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