2017-05-24 6 views
0

私はGeneric Typeとプロトコルを使用する小さなデモを簡単にしています。Swiftプロトコルで使用されている一般的なタイプは動作していません

protocol Food { 

} 

class Meat: Food { 

} 

class Cake: Food { 

} 

protocol EatProtocol { 
    func eat<T: Food>(_: T) 
} 

class Person: EatProtocol { 
    func eat<T>(_: T) where T : Food { 
     print("eat food") 
    } 
} 

class Man: Person { 
    override func eat<T>(_: T) where T : Meat { 
     print("eat meat") 
    } 
} 

class Woman: Person { 
    override func eat<T>(_: T) where T : Cake { 
     print("eat cake") 
    } 
} 

let man = Man() 
let woman = Woman() 
let manyPeople: [EatProtocol] = [man, woman] 

let meat = Meat() 
let cake = Cake() 
let manyFood: [Food] = [meat, cake] 

for (index, people) in manyPeople.enumerated() { 
    let food = manyFood[index] 
    people.eat(food)//error: Cannot invoke 'eat' with an argument list of type '(Food)' 
} 

問題は、私は、forループの項目で右食品を得ることを確信しているが、コンパイラがそのエラーに私

+1

私は、これはXYの問題であることを疑います。これはジェネリックを使用するためのユースケースではないようです(ポリモーフィズムはおそらくもっと意味があります)。しかし、私がその決定を下す前に解決しようとしている実際の問題を理解しなければならないでしょう – Alexander

+0

なぜmanyPeopleの配列ですか? [EatProtocol]はEatProtocol型で、Person型ではありませんか?なぜ男性と女性の両方がケーキと肉を食べることができないのですか? –

+0

@BrianOgden manyPeople配列型[EatProtocol]は[Person]と同じです。この問題では、1つの種類の人が1つの食べ物を食べることができるので、これがエラーの原因です。 – huangxinyu

答えて

1

を与える根本的な問題がここにあります:すべての食べる人は、食品のすべての種類を食べることができます。私は、この特定の例ではと考えることができる最高の安全にキャスト可能な組み合わせを、列挙、および呼び出しを行うためにswitchを使用することです:

protocol Food {} 
class Meat: Food {} 
class Cake: Food {} 

protocol Eater { 
    func eat<T: Food>(_: T) 
} 

class Person: Eater { 
    func eat<T>(_: T) where T: Food { 
     print("eat food") 
    } 
} 

class Man: Person { 
    override func eat<T>(_: T) where T: Meat { 
     print("eat meat") 
    } 
} 

class Woman: Person { 
    override func eat<T>(_: T) where T : Cake { 
     print("eat cake") 
    } 
} 

let eaters: [Eater] = [Man(), Woman()] 
let foods: [Food] = [Cake(), Cake()] 

for (food, eater) in zip(foods, eaters) { 
    switch (food, eater) { 
     case let (meat as Meat, man as Man): man.eat(meat) 
     case let (cake as Cake, woman as Woman): woman.eat(cake) 
     //... 
     default: 
      print("\(eater) (of type: \(type(of: eater))) cannot eat \(food) (of type: \(type(of: food)))") 
      continue 
    } 
} 
+0

はい、動作します!あなたは私を理解して、よかった! – huangxinyu

+1

実際には、スウィフトが 'f:eatは(_:T)のT:肉 'を食べて、「(_:T)を食べなさい。関数はパラメータ型とは反比例しているので、[上書きを許可することはまったく危険です](https://gist.github.com/hamishknight/9f40055541dced330420b83ef04eb7e7)。私は瞬間が来たらバグを報告します。 – Hamish

+1

バグ報告:https://bugs.swift.org/browse/SR-4986 – Hamish

関連する問題