2016-11-18 2 views
4

J'essaye d'écrire ma propre version de IndexingIterator pour augmenter ma compréhension de Sequence. Je n'ai assigné aucun type à Iterator associatetype dans ma structure. Cependant, le compilateur ne s'en plaint pas et j'obtiens une implémentation par défaut de makeIterator.conforme à Sequence et IteratorProtocol dans Swift

Voici mes codes:

struct __IndexingIterator<Elements: IndexableBase>: Sequence, IteratorProtocol { 
    mutating func next() -> Elements._Element? { 
     return nil 
    } 
} 
let iterator = __IndexingIterator<[String]>() 
// this works and returns an instance of __IndexingIterator<Array<String>>. why? 
iterator.makeIterator() 

Je pense qu'il doit y avoir des extensions sur Sequence qui ajoutent l'implémentation par défaut. Ainsi, je l'ai cherché dans Sequence.swift et seulement trouvé cela.

extension Sequence where Self.Iterator == Self, Self : IteratorProtocol { 
    /// Returns an iterator over the elements of this sequence. 
    public func makeIterator() -> Self { 
    return self 
    } 
} 

je pensais que ce serait comme ça:

extension Sequence where Self: IteratorProtocol { 
    typealias Iterator = Self 
    ... 
} 

Ai-je raté quelque chose ou je mal compris l'extension?

+0

Quelqu'un peut-il aider? – Evan

Répondre

0

L'alias de type n'est pas nécessaire, car le type associé Element est déduit de votre implémentation de next().

Voici un exemple simple:

protocol ResourceProvider { 
    associatedtype Resoruce 
    func provide() -> Resoruce; 
} 

struct StringProvider { 
    func provide() -> String { // "Resource" inferred to be "String" 
     return "A string" 
    } 
} 
+0

Je suis d'accord avec vous sur votre exemple, mais je ne pense pas que cela puisse expliquer mon problème. Je pense que le type associé 'Element' dans IteratorProtocol peut être inféré être' _IndexableBase._Element', mais le type associé 'Iterator' dans' Sequence' ne peut pas être déduit car ma définition de '__IndexingIterator' manque d'affectation de type pour' Iterator'. Et j'ai besoin d'une explication pour ça. – Evan

+0

Cette extension que vous avez affichée (l'avant-dernier extrait de code) définit une implémentation par défaut pour les types qui sont à la fois des séquences et des intégrateurs. Cette extension le fait donc par défaut, de tels types se conforment 'Sequence' en retournant eux-mêmes' makeIterator() '. '__IndexingIterator' correspond aux critères, car il s'agit à la fois d'une séquence et d'un itérateur. Par conséquent, il gagne cette implémentation par défaut de 'makeIterator'. Cette implémentation par défaut renvoie un type 'Self', qui se résout à' __IndexingIterator' dans ce contexte. – Alexander

+0

Le compilateur sait également que le type de retour de 'makeIterator' est le type associé' Iterator', donc il met 2 et 2 ensemble pour conclure que 'Iterator' est' __IndexingIterator' – Alexander

0

Il ressemble à la réponse d'Alexandre est correcte. Voici une version bouillie vers le bas, sans utiliser Sequence:

protocol MySequence { 
    associatedtype Iterator: IteratorProtocol 
    func maakeIterator() -> Iterator 
} 

extension MySequence where Self.Iterator == Self, Self : IteratorProtocol { 
    /// Returns an iterator over the elements of this sequence. 
    func maakeIterator() -> Self { 
     return self 
    } 
} 

struct __IndexingIterator<Element>: MySequence, IteratorProtocol { 
    mutating func next() -> Element? { 
     return nil 
    } 
} 

let iterator = __IndexingIterator<[String]>() 
iterator.maakeIterator() 
0

Vous pouvez écrire votre propre itérateur qui confrom à IteratorProtocol, puis écrire ce que vous avez besoin confrom à Sequence.

Assurez-vous d'avoir implémenté la fonction requise.

struct IteratorTest : IteratorProtocol { 
     typealias Element = Int 

     var count : Int 

     init(count :Int) { 
      self.count = count 
     } 

     mutating func next() -> Int? { 
      if count == 0 { 
       return nil 
      }else { 
       defer { 
        count -= 1 
       } 
       return count; 
      } 
     } 
    } 

    struct CountDown : Sequence { 
     typealias Iterator = IteratorTest 
     func makeIterator() -> IteratorTest { 
      return IteratorTest.init(count: 10) 
     } 
    }