2014-06-10 10 views
10

Ich versuche, eine Erweiterung für das Matrix Beispiel aus dem Buch, slightly tweaked to be generic zu schreiben.
Ich versuche, eine Methode namens getRow zu schreiben, die eine Sequenz von Werten in der angegebenen Zeile zurückgibt.Wie gebe ich eine Sequenz in Swift zurück?

In C#, würde ich dieses geschrieben habe:

IEnumerable<T> GetRow (int row) 
{ 
    return Enumerable 
     .Range (0, this.columns) 
     .Select ((column) => this.grid[row, columns]); 
} 

oder alternativ

IEnumerable<T> GetRow (int row) 
{ 
    for (var column = 0; column < this.columns; column++) { 
     yield return this.grid[row, column]; 
    } 
} 

Ich bin mir nicht sicher, wie dies obwohl in Swift zu tun.

Sequence scheint das Äquivalent zu IEnumerable<T> zu sein, aber ich verstehe nicht, warum es typealias statt nur wird definiert als Sequence<T> (see also this) verwendet. Definieren einer Methode, die generische Sequence<T> kehrt nicht funktioniert:

extension Matrix { 
    // Cannot specialize non-generic type 'Sequence' 
    func getRow<T>(index: Int) -> Sequence<T> { 
     return map(0..self.columns, { self[index, $0] }) 
    } 
} 

Dann habe ich los <T> (aber, wie es sein generic soll?):

extension Matrix { 
    func getRow(index: Int) -> Sequence { 
     return map(0..self.columns, { self[index, $0] }) 
    } 
} 

Dies kompiliert! Allerdings kann ich es nicht verwenden:

var row = grid.getRow(0) 
// 'Sequence' does not conform to protocol '_Sequence_' 
for i in row { 
    println("\(i)") 
} 

Wie kann ich geben richtig map Ergebnis so kann es in einer for..in Schleife verbraucht werden?

Mehr zu diesem Thema: Associated Type Considered Weird

Antwort

9

Joe Groff suggested das Ergebnis in SequenceOf<T> einzuwickeln:

extension Matrix { 
    func getRow(index: Int) -> SequenceOf<T> { 
     return SequenceOf(map(0..self.columns, { self[index, $0] })) 
    } 
} 

Tat das funktioniert, aber wir hatten map Ergebnis in eine Hilfsklasse wickeln die unterscheidet sich von, wie ich es in C# mache.

Ich muss zugeben, dass ich noch nicht verstehen, warum Sequence und Generator Verwendung typealias und sind nicht generische Protokolle (wie IEnumerable<T> in C#).Es gibt eine interessante laufende Diskussion über diese Unterscheidung so dass ich ein paar Links für einen neugierigen Geist verlassen werden:

  1. Associated Types Considered Weird
  2. Associated types vs. type parameters - reason for the former?
  3. Abstract Type Members versus Generic Type Parameters in Scala
  4. Generics and protocols
+0

Danke für all diese Links - sehr geschätzt. – ColinE

+0

Vergessen Sie nicht, dass SequenceOf aus den letzten Versionen von Swift entfernt wurde. –

1

Ich glaube, Sie durch die Swift-Compiler verleitet werden (die im Moment ein bisschen flockig ist). Der Typ für Ihren Bereich 0..self.columns ist, was kein Sequence oder Collection ist, also glaube ich nicht, dass er über map verwendet werden kann.

Die Umsetzung funktioniert für mich:

extension Matrix { 
    func getRow(index: Int) -> T[] { 
    var row = T[]() 
    for col in 0..self.columns { 
     row.append(self[index, col]) 
    } 
    return row 
    } 
} 
+0

Ich werde Datei ein Radar ... Wie halte ich die Sequenz faul? –

+0

@Dan sind sie faul? Wenn ich eine Map auf einem Array ausführe, aber nichts mit den Ergebnissen mache, wird die Schließung für alle Array-Werte noch ausgeführt. – ColinE

+0

Seltsam! Ich dachte, wenn es kein Array zurückgibt, dann muss es faul sein. Ich werde das überprüfen. –

Verwandte Themen