swift – 类型’T’不符合协议’EntityType’

我认为这里的类型关系相当简单,但我错过了错误的原因.错误是:“类型’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> {
}

T是Thing的子类型; Thing是实现EntityType的EntityWithStringIdentifier的子类型.那么,为什么错误呢?

显然,使用以下方法可以避免错误:

class ThingManager<T:Thing where T:EntityType> : BaseEntityManager<T> {
}

然后可以用Thing实例化ThingManager(暗示Thing首先实现了EntityType ……)

var tm = ThingManager<Thing>()

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

最佳答案 随着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的约定.

点赞