【问题标题】:Using swift generics in method signature with swift5使用 swift5 在方法签名中使用 swift 泛型
【发布时间】:2022-06-10 21:32:16
【问题描述】:
protocol AnimalFeed {
    init()
}

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

struct Hay: AnimalFeed {}
struct Carrot: AnimalFeed {}

struct Cow: Animal {
    func eat(_ food: Hay) {
        print("I eat hay")
    }
}

struct Rabbit: Animal {
    func eat(_ food: Carrot) {
        print("I eat carrot")
    }
}

struct Farm {
    func feed<T: Animal>(_ animal: T) {
        animal.eat(T.Feed())
    }

    func feedAll<T: Animal>(_ animals: [T]) {
        animals.forEach { feed($0)}
    }
}

let farm = Farm()
farm.feed(Rabbit())
farm.feedAll([Cow(), Rabbit()])

最后一行导致错误:表达式类型不明确,没有更多上下文 我们如何解决这个问题? 我希望能够传递一个符合 Animal 协议的结构数组。

【问题讨论】:

  • 您需要类型擦除。 This优秀文章详细讲解。
  • 观看 WWDC 2022 的“拥抱 Swift 泛型”。Swift 5.7 将通过any Animal 提供智能解决方案

标签: swift generics swift-protocols


【解决方案1】:

这不能在 Swift 5.5 中完成

当你写作时

func feedAll<T: Animal>(_ animals: [T]) {
    animals.forEach { feed($0)}
}

你是说,“农场可以喂一组任何一种动物。”编译器查找符合 Animal、Cow 和 Rabbit 的单一类型,但找不到。您真正想要的是,“Farm 可以提供符合 Animal 的任何对象的数组。”

func feedAll(_ animals: [Animal]) {
    animals.forEach { feed($0) }
}

但这激怒了 Swift 5.5

Protocol 'Animal' 只能用作通用约束,因为它具有 Self 或关联的类型要求

Protocol 'Animal' 作为一种类型不能符合协议本身

您可以通过构造一个“盒子”类型来解决此问题,该类型捕获内部类型(通常称为类型擦除)并将数组中的每个动物显式包装在一个盒子中。在 Swift 5.7 中,这种解决方法应该更容易,因为编译器可以(在大多数情况下)通过使用 any Animal 为您做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2016-10-26
    • 1970-01-01
    • 2018-11-28
    • 1970-01-01
    相关资源
    最近更新 更多