2015-01-15 8 views
5

ich ein ziemlich gutes Verständnis der OO-Programmierung haben und Swift jedoch ein Bereich, der lässt mich wirklich ratlos ist Generatoren und Sequenzen (Ich bin gut mit dem Konzept der Protokolle durch die Weg).Generics mit Generatoren und Sequenzen in Swift

ZB abgeschlossen ich diese Übung von dem Swift-Führer (Apple)

„-Experiment die anyCommonElements Funktion Ändern einer Funktion zu machen, das eine Anordnung der Elemente zurückgibt, die beliebige zwei Sequenzen gemeinsam haben.“

Drehen dieses:

func​ ​anyCommonElements​ <​T​, ​U​ ​where​ ​T​: ​SequenceType​, ​U​: ​SequenceType​, ​T​.​Generator​.​Element​: ​Equatable​, ​T​.​Generator​.​Element​ == ​U​.​Generator​.​Element​> (​lhs​: ​T​, ​rhs​: ​U​) -> ​Bool​ { 
    for​ ​lhsItem​ ​in​ ​lhs​ { 
     for​ ​rhsItem​ ​in​ ​rhs​ { 
      if​ ​lhsItem​ == ​rhsItem​ { 
       return​ ​true 
      } 
     } 
    } 
    return​ ​false 
} 

In diese:

func anyCommonElements <T, U where T: SequenceType, U: SequenceType, T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs: T, rhs: U) -> [T.Generator.Element]? { 
var commonElements:[T.Generator.Element]? = nil 
    for lhsItem in lhs { 
     for rhsItem in rhs { 
      if lhsItem == rhsItem { 
       if (commonElements == nil) 
       { 
        commonElements = [] //init the array if not already 
       } 
       commonElements?.append(lhsItem) //add matching item to the array 
      } 
     } 
    } 
    return commonElements? //return nil or array of matched elements 
} 

Ich bin zufrieden mit der Lösung, die ich geschrieben habe und es funktioniert gut, einschließlich der optionalen Rückkehr, aber ich bin verloren, warum die Art der commonElements zurückgeben Array Bedürfnisse dieser sein:

var commonElements:[T.Generator.Element] 

Anstatt dies:

var commonElements:[T] 

ich ein gutes Stück über das Thema gelesen haben, einschließlich:

https://schani.wordpress.com/2014/06/06/generators-in-swift/

http://robots.thoughtbot.com/swift-sequences

http://natashatherobot.com/swift-conform-to-sequence-protocol/

Aber ich bin völlig verloren noch - kann jemand bitte erklären helfen, dies in einfachen Worten oder ist es nur ein wenig abstrakt und nicht leicht zu beschreiben?

es wirklich schätzen würde, Danke, John

+0

Ist das Problem, dass Sie nicht verstehen, wo die Namen 'Generator' und' Sequence' kommen? Oder verstehst du nicht, was sie bedeuten? – matt

+0

** Als Nebenbei beantwortet das die Frage nicht, sondern adressiert das Experiment **: Es wäre interessanter, einen Generator zurückzugeben, damit Lazy-Loading noch wirksam sein kann. Das Problem, zu dem Sie aufgefordert wurden, zu lösen, zwingt Sie, alle zu vergleichenden Elemente zu laden und dann ein gefülltes Array zurückzugeben. –

+0

@matt beides denke ich! – Woodstock

Antwort

12

T ist ein Sequenztyp. Der Einfachheit halber nehmen wir einen speziellen und vertrauten Fall und sagen T ist ein Array.

Dann ist die Art der Sache im Array enthalten T.Generator.Element. Dies liegt an der Art, wie die Array-Struktur definiert ist. Beachten Sie, dass Array ein Generic ist. Es ist ein SequenceType, ein (generisches) Protokoll mit einem leeren Typ-Alias ​​Generator, der als GeneratorType definiert ist, der seinerseits ein (generisches) Protokoll ist, das einen leeren Typ-Alias ​​Element hat. Wenn das generische Objekt spezialisiert ist, werden diese leeren Aliase mit einem tatsächlichen Typ "ausgefüllt". Alle Sequenzen sind so. Wenn also T ein Array ist, dann bedeutet T.Generator.Element "die tatsächliche Art von diese Array tatsächlichen Elemente".

So bedeutet [T.Generator.Element] „eine Anordnung von der gleichen Art von Element, wie die Elemente des ursprünglichen Arrays.

Ihre vorgeschlagene Ausdruck, [T], würde eine Reihe von Arrays, bedeutet das nicht, was wir wollen.

Okay, verallgemeinern Sie jetzt T zu jeder Sequenz (Array, Zeichenkette usw.) und diese Erklärung funktioniert weiter.

+1

Es könnte Ihnen helfen, mein neues Swift Tutorial zu lesen; Hier ist der Abschnitt über Generika: http://www.apeth.com/swiftBook/ch04.html#_generics – matt

+0

JA, das ist eine wunderbare Erklärung. Du bist eine Legende. Ok noch eine Sache - wenn das 'Element' tatsächlich der Typ ist. Was ist der Generator? ps. lese jetzt dein Tutorial – Woodstock

+0

Einen Generator zu schreiben, wie @IanMacdonald angedeutet hat, ist knifflig. Es muss in der Lage sein, von einem Mitglied zum nächsten zu gelangen, vorzugsweise träge. Sehen Sie sich das Video der WWDC 2014 zu Advanced Swift an, in dem darüber gesprochen wird. – matt

1

Die Antwort des Autors ist für die neuste Version von Swift nicht länger gültig. Hier ist ein Update, das mit Version 3.0.1 kompatibel ist. Sie haben das Generieren eines generischen Arrays vereinfacht. Hinweis: Ich habe ursprünglich [Any] -Arrays verwendet, aber den Code basierend auf dem Feedback unten aktualisiert.

func showCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Iterator.Element] 
    where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element { 
     var result:[T.Iterator.Element] = [] 
     for lhsItem in lhs { 
      for rhsItem in rhs { 
       if lhsItem == rhsItem { 
        result.append(lhsItem) 
       } 
      } 
     } 
     return result 
} 

Sie können den Code mit den folgenden Befehlen testen:

showCommonElements([1, 2, 3, 4, 5], [4, 7, 3]) 
showCommonElements(["apple", "banana", "orange", "peach"], ["orange", "pear", "apple"]) 
+0

Ich schätze die Antwort, aber ich glaube, das ist völlig falsch. Sie sollten niemals Any mit Generika verwenden. Wenn Sie Any verwenden, verlieren Sie die Typinformation, die Generika beibehalten sollen. Wo hast du das von Apple verwendet gesehen? Wenn Sie das tun, wie Sie vorgeschlagen haben, erhält der Aufrufer der Funktion ein "Any" -Array. Generics ermöglichen die Rückgabe eines typisierten Arrays. – Woodstock

+1

Überprüfen Sie dies, führen Sie diesen Code aus und es zeigt, wie die Typinformationen verloren gehen. http: //swiftlang.ng.bluemix.net/#/repl/5891c7af7a5c2d1425c7490c – Woodstock

+0

Ich sehe, danke für die konstruktive Kritik. Ich bin neu in Swift und lerne immer noch die richtigen Übungen. Vielleicht wäre der bessere Weg, alle Instanzen von "Any" in meinem Code durch "T.Iterator.Element" zu ersetzen, um Typinformationen zu erhalten. Sie verwenden optionale Arrays in Ihrem Sandbox-Beispiel. Gibt es dafür einen bestimmten Grund? Wie ich schon sagte, ich bin neu in der Sprache, also versuche ich, gute Praktiken zu lernen. – ToneDaBass