Как вернуть последовательность в Swift?
Я пытаюсь написать расширение для Matrix
примера из книги, слегка изменено, чтобы быть общим.
Я пытаюсь написать метод под названием getRow
, который возвращает последовательность значений в данной строке.
В С# я бы написал следующее:
IEnumerable<T> GetRow (int row)
{
return Enumerable
.Range (0, this.columns)
.Select ((column) => this.grid[row, columns]);
}
или, альтернативно,
IEnumerable<T> GetRow (int row)
{
for (var column = 0; column < this.columns; column++) {
yield return this.grid[row, column];
}
}
Я не уверен, как это сделать в Swift, хотя.
Sequence
кажется эквивалентным IEnumerable<T>
, но я не понимаю, почему он использует typealias
вместо того, чтобы просто определяться как Sequence<T>
(см. также это). Определение метода, возвращающего общий Sequence<T>
, не работает:
extension Matrix {
// Cannot specialize non-generic type 'Sequence'
func getRow<T>(index: Int) -> Sequence<T> {
return map(0..self.columns, { self[index, $0] })
}
}
Затем я избавился от <T>
(но как он должен быть общим?):
extension Matrix {
func getRow(index: Int) -> Sequence {
return map(0..self.columns, { self[index, $0] })
}
}
Это компилируется! Однако я не могу его использовать:
var row = grid.getRow(0)
// 'Sequence' does not conform to protocol '_Sequence_'
for i in row {
println("\(i)")
}
Как правильно напечатать результат map
, чтобы его можно было использовать в цикле for..in
?
Подробнее об этой проблеме: Связанный тип считается странным
Ответы
Ответ 1
Joe Groff предложил обернуть результат в SequenceOf<T>
:
extension Matrix {
func getRow(index: Int) -> SequenceOf<T> {
return SequenceOf(map(0..self.columns, { self[index, $0] }))
}
}
В самом деле, это работает, но нам пришлось обернуть результат map
в класс-помощник, который отличается от того, как я это делаю в С#.
Я должен признать, что я еще не понимаю, почему Sequence
и Generator
используют typealias
и не являются общими протоколами (например, IEnumerable<T>
в С#). Есть интересная текущая дискуссия об этом различии, поэтому я оставлю несколько ссылок для любопытного ума:
Ответ 2
Я думаю, что вы вводите в заблуждение компилятор Swift (который сейчас немного шелушится). Тип для вашего диапазона 0..self.columns
- Range<Int>
, который не является Sequence
или Collection
, поэтому я не думаю, что его можно использовать через map
.
Реализация работает для меня:
extension Matrix {
func getRow(index: Int) -> T[] {
var row = T[]()
for col in 0..self.columns {
row.append(self[index, col])
}
return row
}
}