2016-03-08 4 views
2

Я думаю, что мое познание для типов Swift/протоколов/дженериков переполнилось. Я использую шаблон расширения «входной поток байтов», делая что-то вроде:Swift Почему мой генераторный протокол не работает?

extension GeneratorType where Element == UInt8 { 
    func foobar() { 
     ... 
    } 
} 

Он работал в прошлом для простых вещей. И сегодня я играл со следующим:

protocol Unpackable { 
    static func unpack(inout input:IndexingGenerator<[UInt8]>) -> Self 
} 

extension UInt8:Unpackable { 
    static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt8 { 
     return input.next()! 
    } 
} 

extension UInt16:Unpackable { 
    static func unpack(inout input:IndexingGenerator<[UInt8]>) -> UInt16 { 
     return UInt16(input.next()!) | (UInt16(input.next()!) << 8) 
    } 
} 

Хорошо работает. Но если я пытаюсь поставить два вместе с чем-то вроде

extension GeneratorType where Element == UInt8 { 
    func unpackAll() -> (UInt8, UInt16) { 
     return (UInt8.unpack(&self), UInt16.unpack(&self)) 
} 

тогда я получаю следующее сообщение об ошибке:

Cannot convert value of type 'Self' to expected argument type 'IndexingGenerator<[UInt8]>' 

ли не IndexingGenerator соответствовать GeneratorType? Является ли его элемент не UInt8? Является ли ошибка при использовании IndexingGenerator? Я не могу указать типы аргументов как GeneratorType (хотя я действительно хотел бы иметь возможность).

Я все еще жду, чтобы лампочка мерцала для типов Swift. В некоторые дни мне очень нравится этот язык. В другие дни, я чувствую, что я кричу на свою собаку, пытаясь заставить его прийти, и он просто смотрит на меня, не двигаясь, затем все равно поворачивается и преследует улицу.

+0

"Разве не IndexingGenerator соответствует GeneratorType" Да, но не каждый GeneratorType является IndexingGenerator. – matt

+0

Я сделал аргументы 'IndexingGenerator <[UInt8]>' только потому, что не мог понять, как это сделать в общем. Мне, честно говоря, все равно, что это IndexingGenerator. Я был бы в порядке с Генератором любого типа, если бы он производил UInt8. Есть ли способ иметь аргумент, который является протоколом соответствующей спецификации? –

+0

Является ли трюк объявлением * нового * протокола, который соответствует «GeneratorType» и каким-то образом сдерживает соответствующие типы, чтобы иметь элементы 'UInt8'? –

ответ

2

Попробуйте это:

extension GeneratorType where Element == UInt8 { 
    func unpackAll() -> (UInt8, UInt16)? { 
     guard let _self = self as? IndexingGenerator<[Element]> else { return nil } 
     var vSelf = _self 
     return (UInt8.unpack(&vSelf), UInt16.unpack(&vSelf)) 
    } 
} 

Update:

protocol Unpackable { 
    static func unpack<T : GeneratorType where T.Element == UInt8>(inout input:T) -> Self 
} 

extension UInt8: Unpackable { 
    static func unpack<T : GeneratorType where T.Element == UInt8>(inout input: T) -> UInt8 { 
     return input.next()! 
    } 
} 

extension UInt16: Unpackable { 
    static func unpack<T : GeneratorType where T.Element == UInt8>(inout input: T) -> UInt16 { 
     return UInt16(input.next()!) | (UInt16(input.next()!) << 8) 
    } 
} 

extension GeneratorType where Element == UInt8 { 
    mutating func unpackAll() -> (UInt8, UInt16) { 
     return (UInt8.unpack(&self), UInt16.unpack(&self)) 
    } 
} 
+0

Могли бы сказать 'guard var vSelf' и быть на одну строку короче :) – matt

+0

@matt LOL. Честно говоря, я никогда не использую 'var' с' guard', и я предполагаю, что не могу этого сделать! Как глупо я ... Спасибо за подсказку. –

+0

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