Изменение метода generate() для подкласса класса, соответствующего "SequenceType"

Допустим, у меня есть общий класс Parent<P>, что соответствует SequenceType протокол, реализуя generate() метод:

class Parent<P> {
    //...
}

extension Parent: SequenceType {
    func generate() -> GeneratorOf<[P]> {
    //...

    return GeneratorOf<[P]> {
        //return the next element, or nil to stop
    }
}

Теперь generate() метод явно не просто возвращает элементы типа P, но [P],

Теперь давайте реализуем подкласс Child<C>:

class Child<C>: Parent<C> {
    //...
}

Child также должен соответствовать SequenceType, но не должен возвращать элементы типа [C], скорее C,
По логике вещей я бы попытался реализовать собственный generate() метод:

extension Child: SequenceType {
    func generate() -> GeneratorOf<C> {
    //...

    return GeneratorOf<C> {
        //return the next element, or nil to stop
    }
}

Это не работает, хотя, и Swift выдает ошибку:

<stdin>: error: type 'Child<C>' does not conform to protocol '_Sequence_Type'
extension Child: SequenceType {
^
Swift._Sequence_Type: note: multiple matching functions named 'generate()' with type '() -> Child<C>.Generator'
func generate() -> Generator
^
<stdin>: note: candidate exactly matches [with Generator = GeneratorOf<C>]
func generate() -> GeneratorOf<C> {
^
<stdin>: note: candidate exactly matches [with Generator = GeneratorOf<[C]>]
func generate() -> GeneratorOf<[P]> {
^
<stdin>: error: type 'Child<C>' does not conform to protocol 'SequenceType'
extension Child: SequenceType {
^
Swift.SequenceType: note: multiple matching functions named 'generate()' with type '() -> Child<C>.Generator'
func generate() -> Generator
^
<stdin>: note: candidate exactly matches [with Generator = GeneratorOf<C>]
func generate() -> GeneratorOf<C> {
^
<stdin>: note: candidate exactly matches [with Generator = GeneratorOf<[C]>]
func generate() -> GeneratorOf<[P]> {

В чем здесь проблема, и как я могу это исправить?


Обновление № 1:

Таким образом, проблема, кажется, решена путем применения подхода @rintaro, заключающегося только в определении typealias за Generator в Child класс
Но, как обсуждалось в комментариях @AirspeedVelocity и @NateCook, это не очень жизнеспособный подход, потому что Child класс также может быть подклассом.

Также было указано, что можно создать свойство экземпляра (которое я предполагаювычисленным), возвращающее последовательность нужных элементов:

class Parent<P> {
    var asSequence: [[P]] {
        //some kind of getter
    }

    //...
}

class Child<C>: Parent<C> {
    override var asSequence: [C] {
        //some kind of getter
    }

    //...
}

Экземпляры могут быть использованы в for-in-loop:

for element in someParent.asSequence {
    //element is of type [P]
}

for element in someChild.asSequence {
    //element is of type C
}

Это был бы "лучший" подход?

Обновление № 1.1:

Как подсказал @MichaelWelch, имена свойств (asSequence) может привести к путанице в этом случае, поскольку они возвращают разные типы.
Это кажется уместным, но зависит от ситуации. Но в целом двусмысленности следует избегать.

1 ответ

Решение

Кажется, ты можешь. Явные typealias для Generator только в Child сделал трюк. Тем не менее, я также думаю, что вы не должны так делать...

class Parent<P> {
    var _src:[[P]] = []
}

extension Parent: SequenceType {

    func generate() -> GeneratorOf<[P]> {

        var g = _src.generate()

        return GeneratorOf<[P]> {
            return g.next()
        }
    }

}

class Child<C>: Parent<C> {
    var _ary:[C] = []
}

extension Child: SequenceType {

    typealias Generator = GeneratorOf<C> // <-- HERE

    func generate() -> GeneratorOf<C> {

        var g = _ary.generate()

        return GeneratorOf<C> {
            return g.next()
        }
    }
}
Другие вопросы по тегам