2017-09-17 14 views
2

where句では、ジェネリックパラメータを特定のプロトコルから継承するプロトコルに制限することはできません。プロトコルから継承するプロトコルにジェネリックパラメータを制限する

protocol Edible {} 
protocol PetFood: Edible {} 
struct CatFood: PetFood {} 
struct Rocks {} 

func eat<T: Edible>(_ item: T) -> String { 
    return "Just ate some \(type(of: item))" 
} 

let food: CatFood = CatFood() 
eat(food) //"Just ate some CatFood" 

let moreFood: PetFood = CatFood() 
//eat(moreFood) //Cannot invoke 'eat' with an argument list of type '(PetFood)' 

func eatAnything<T>(_ item: T) -> String { 
    return "Just ate some \(type(of: item))" 
} 

eatAnything(moreFood) //This works, obviously 
eatAnything(Rocks()) //But, of course, so does this... 

プロトコルの種類を許可するようeatAnything()を制限する方法はありますが、唯一のEdibleから継承したもの?あなたの例では

答えて

1

それがで置き換えることができるので、汎用的な関数の定義は、任意の意味をなさない:

func eat(_ item: Edible) -> String { 
    return "Just ate some \(type(of: item))" 
} 

しかし、あなたは本当に、あなたが知っておくべき一般的な機能を使用する場合:

  1. 総称関数の定義

    • func eat<T: Edible>(_ item: T) -> String { ... }
    • func eat<T>(_ item: T) -> String where T: Edible { ... }
    • func eat<T: Edible>(_ item: T) -> String where T: Equatable { ... }
  2. プロトコルはダイナミック型であるので、彼らは、遅延バインディングを使用します。一般的なコードはコンパイル時に正常に変換され、早期の結合を必要と

    • 事前バインディング(コンパイル時):変数は通常の静的、宣言型の手段
    • て、実行時に行使される前に、タイプが知られています
    • レイトバインド(実行時):実行時に変数が実行されるまで型が不明です。通常は代入によって行われますが、型を強制する他の手段があります。動的に型指定された言語は、これを基礎となる機能と呼びます。
  3. 汎用関数は、プロトコル互換性のある型で定義できますが、コンパイラはこのプロトコルを型として渡すことはできません。そのタイプはTです。一般的な関数型に渡された特定のタイプ(クラス、構造体、列挙型、...)


let a: [Int] = [1,2,3] 
let b: [CustomStringConvertible] = [1, "XYZ"] 

a.index(of: 2) // 1 
b.index(of: "XYZ") // error 
+0

まあでなければならない、必ず - それは質問を実証するだけの簡単な例です。 – andyvn22

+0

@ andyvn22私の答えを更新しました –

関連する問題