输入' T'不符合协议' EntityType'

时间:2015-06-05 21:55:03

标签: swift

我认为这里的类型关系相当明显,但我错过了错误的原因。错误是:"键入' T'不符合协议' EntityType'" (在ThingManager):

//
protocol EntityType {
  typealias Identifier
  var identifier : Identifier { get }
}

class EntityWithStringIdentifier : EntityType {
  var identifier : String
  init (i:String) { self.identifier = i }
}

class Thing : EntityWithStringIdentifier {}

//
protocol EntityManager {
  typealias Entity : EntityType
  func has (entity:Entity) -> Bool
}

class BaseEntityManager<Entity:EntityType> : EntityManager {
  func has (entity:Entity) -> Bool { return true }
}

// Type 'T' does not conform to protocol 'EntityType'
class ThingManager<T:Thing> : BaseEntityManager<T> {
}

TThing的子类型; Thing是实现EntityWithStringIdentifier的{​​{1}}的子类型。 那么,为什么错误

显然,使用以下内容可以避免错误:

EntityType

然后可以使用class ThingManager<T:Thing where T:EntityType> : BaseEntityManager<T> { } 实例化ThingManager(首先暗示Thing已实施Thing ...)

EntityType

从类型的角度来看,有没有更好的方法来实现这种DAO模式?

1 个答案:

答案 0 :(得分:2)

随着Swift 2.0的发布,以早期版本的Swift来回答这个问题似乎毫无意义,很快就会过时。我可以确认这个问题 - 我认为是一个bug - 仍然存在于Swift 2.0中。但是,我可以建议一种稍微不同的方式来组织代码,以缓解问题,同时仍然有一个干净的实现:跳过ThingManager类并改为使用协议扩展。

因此,将所有代码保留为BaseEntityManager,您必须:

// NOTE "where Entity: Thing". This is the key.
extension EntityManager where Entity: Thing {
  func useAThing(thing: Thing) {

  }
}

let tm = BaseEntityManager<Thing>()
tm.useAThing(Thing(i: "thing"))

我怀疑这最终将成为做事的“快捷方式”。 Swift的泛型对我来说简直很奇怪。他们经常违反最低惊喜原则,恕我直言。但如果你了解他们的怪癖,最终他们会非常强大。这种方法的唯一缺点是访问修饰符和封装。 useAThing方法无权访问EntityManagerBase的私有状态,根据您的具体情况,这可能是也可能不是问题。

最后,如果采用这种方法,我建议重命名。 BaseEntityManager如果你从不继承它,那就像是错误的名字。相反,我会将其称为EntityManager并将协议重命名为EntityManagerType以遵循Apple的惯例。