Swift:从泛型调用非泛型函数?

时间:2015-02-28 23:19:49

标签: swift generics

我有许多饥饿的FoodMonster人可以munch许多不同类型的食物。怪物对每种类型的munch都有单独的重载方法。

我希望建立一个管理很多怪物的MonsterPack,并且可以为FoodMonster munch protocol Cookie {} protocol Lettuce {} protocol FoodMonster { func munch(Cookie) func munch(Lettuce) } struct MonsterPack { var monsters = [FoodMonster]() func feed<T>(food: T) { for monster in monsters { monster.munch(food) } } } 提供所有类型的食物。我已经实现了这样:

MonsterPack.feed

不幸的是,这个FoodMonster的实现没有编译,因为它是通用的,munch不能像他们想要的那样feed任何类型的值。

我有什么方法可以定义FoodMonster,以便我可以使用munch 可以 {{1}}的任何值来调用它吗?

2 个答案:

答案 0 :(得分:2)

首先将LettuceCookie之间的共同点视为Food

protocol Food {}
protocol Lettuce : Food {}
protocol Cookie  : Food {}

然后指定你feed怪物food

func feed<T:Food>(food: T) {
    for monster in monsters {
        monster.munch(food)
    }
}

并使munch本身通用为:

protocol FoodMonster {
  func munch<T:Food> (food:T)
}

答案 1 :(得分:1)

GoZoner的解决方案很有吸引力,但实际上只是子类化。事实上,它与此相同(注意缺少T):

protocol Food {}
protocol Lettuce : Food {}
protocol Cookie  : Food {}

protocol FoodMonster {
    func munch(food: Food)
}

struct MonsterPack {
    var monsters = [FoodMonster]()

    func feed(food: Food) {
        for monster in monsters {
            monster.munch(food)
        }
    }
}

根本不需要仿制药。在这种情况下,类型参数化确实没有意义,因为您只是依赖于协议。没有理由说“T,T是食物。”那就是“食物”。 (这种过度参数化非常普遍,你应该经常观察它。在你只是意味着“符合”的情况下使用泛型很容易。)

如果你可以使用一个协议,使Lettuce和Cookie都有一些共同的方法,那真是太棒了。但是在给定的例子中这是不可能的。我没有办法在Cookie上调用。我从你的问题中得知,那里确实有一套特定的食物,一个怪物必须能够以特定的方式吃掉它们。如果是这种情况,那么任何真正的怪物都会在munch中进行类型检查。这不是子类化。这是一个sum-type,在Swift中称为enum。

enum Food {
    case Cookie
    case Lettuce
}

protocol FoodMonster {
    func munch(Food)
}

struct MonsterPack {
    var monsters = [FoodMonster]()

    func feed(food: Food) {
        for monster in monsters {
            monster.munch(food)
        }
    }
}

struct RealMonster {
    func feed(food: Food) {
        switch food {
        case .Cookie: break // Do the cookie thing
        case .Lettuce: break // Do the lettuce thing
        }
    }
}

现在我所说的是“如果你想成为一个怪物,你将必须能够咀嚼所有这些可能没有共同协议的东西。”如果这就是你的意思,那么enum就是你的工具,而不是子类,协议或泛型。