2

プロトコルの一部であるジェネリック関数Selfの句の一部として使用しようとすると、問題が発生します。where

たとえば、次のプロトコルと汎用関数が定義されているとします。

protocol Animal {
    associatedtype FoodSource
    func eat(_ food:FoodSource)
}

// The where clause specifies that T2 must conform to
// whatever type is T1's FoodSource associated type 
func feed<T1: Animal, T2>(animal:T1, food:T2) where T2 == T1.FoodSource {
    animal.eat(food)
}

関数 Feed は、角かっこで囲まれたステートメントを使用して、最初のパラメーターがAnimalプロトコルに準拠する必要があることを宣言します。この句を使用whereして、2 番目のパラメーターの型が最初のパラメーターの関連付けられた型に準拠する必要があることを宣言します。

この汎用関数の要件に準拠するクラスを作成することは可能であり、すべてが完全に機能します。例えば:

protocol Meat {}
protocol Vegetable {}

class Rabbit : Animal {
    typealias FoodSource = Vegetable
    func eat(_ food:FoodSource) {
        print("the Rabbit ate the \(type(of:food))")
    }
}

class Lion : Animal {
    typealias FoodSource = Meat
    func eat(_ food:FoodSource) {
        print("the Lion ate the \(type(of:food))")
    }
}

class Carrot : Vegetable {}
class Steak : Meat {}
class ChickenSalad : Meat, Vegetable {}

// works because Carrot conforms to Vegetable
// prints: "the Rabbit ate the Carrot"
feed(animal: Rabbit(), food: Carrot())

// works because Steak conforms to Meat
// prints: "the Lion ate the Steak"
feed(animal: Lion(), food: Steak())

// works because ChickenSalad conforms to Meat
// prints: "the Lion ate the ChickenSalad"
feed(animal: Lion(), food: ChickenSalad())

// works because ChickenSalad conforms to Vegetable
// prints: "the Rabbit ate the ChickenSalad"
feed(animal: Rabbit(), food: ChickenSalad())

ここまでは順調ですね。

ただし、プロトコルの一部としてジェネリックの同じパターンを実装すると、機能しなくなります。

protocol Food {
    func feed<T:Animal>(to:T) where Self == T.FoodSource
}

extension Food {
    func feed<T:Animal>(to animal:T) where Self == T.FoodSource {
        animal.eat(self)
    }
}

class SteakSalad : Food, Meat, Vegetable {}

SteakSalad().feed(to: Lion())

このブロックを実行すると、次のエラーがスローされます。

error: generic parameter 'T' could not be inferred
SteakSalad().feed(to: Lion())
             ^

目的の動作を実現する方法はありますか?

4

1 に答える 1