2015-06-05 2 views
4

Я думаю, что отношения типов довольно просты здесь, и все же мне не хватает причины ошибки. Ошибка: "Type 'Т' не соответствует протоколу 'EntityType'" (в ThingManager):Тип 'T' не соответствует протоколу 'EntityType'

// 
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 является подтипом EntityWithStringIdentifier, который реализует EntityType. Итак, почему ошибка?

Видимо ошибка преодолимо с помощью:

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

, а затем можно создать экземпляр ThingManager с Thing (подразумевающее Thing реализован EntityType в первую очередь ...)

var tm = ThingManager<Thing>() 

От А типа, есть ли лучший способ реализовать такой тип DAO?

+0

Я не понимаю, почему вы так поступаете? Этот запах очень сложный код для простого решения. Вы можете лучше объяснить, что хотите? – ViTUu

+0

@ViTUu Я думаю, что GoZoner хочет сделать, это добиться некоторого полиморфизма. Это на самом деле выглядит для меня довольно простой реализацией. –

ответ

2

С объявлением Swift 2.0 кажется бессмысленным ответить на этот вопрос в терминах более ранних версий Swift, которые очень скоро будут устаревшими. Я могу подтвердить, что эта проблема, которая, как я считаю, является ошибкой, все еще существует на момент написания этой статьи в 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.

Смежные вопросы