【问题标题】:Swift Generic type used in Protocol not work协议中使用的 Swift 通用类型不起作用
【发布时间】:2017-05-24 02:32:27
【问题描述】:

我将我的麻烦简化为一个关于使用通用类型和协议的小演示。这里是代码。

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-loop 项目中得到正确的食物,但编译器给了我这个错误

【问题讨论】:

  • 我怀疑这是一个 XY 问题。这似乎根本不是使用泛型的用例(多态性可能更有意义),但我必须先了解您要解决的真正问题,然后才能做出决定
  • 为什么数组 manyPeople: [EatProtocol] 是 EatProtocol 类型而不是 Person 类型?为什么男人和女人不能同时吃饼和肉?
  • @BrianOgden manyPeople 数组类型 [EatProtocol] 与 [Person] 相同。在这个问题中,一种人只能吃一种食物,这就是错误发生的原因。

标签: swift generics inheritance protocols


【解决方案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
    }
}

【讨论】:

  • 实际上这里还有一个更可怕的问题——Swift 允许用func eat&lt;T&gt;(_: T) where T: Meat 覆盖eat&lt;T&gt;(_: T) where T: Food。函数的参数类型是逆变的,所以permitting the override is nonsense/downright dangerous。有时间我会提交一个错误。
  • @Hamish,是的,你是对的,在这种情况下,我必须保证有人会得到正确的食物,就像你总是给数组提供正确的下标。
  • @Hamish 当我昨晚看到这个时,我在想这没有意义。我很高兴我不会发疯:p
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多