Подтвердить что ты не робот

Любой способ быстро перебрать кортеж?

Мне любопытно, как сделать цикл for с кортежем в swift.

Я знаю, что для доступа к каждому члену вы можете использовать точечную нотацию, используя номер индекса

var tupleList = ("A",2.9,3,8,5,6,7,8,9)

for each in tupleList {
    println(each)
}

//Ошибка: тип не соответствует последовательности протоколов

4b9b3361

Ответ 1

Да, вы можете!

func iterate<C,R>(t:C, block:(String,Any)->R) {
    let mirror = reflect(t)
    for i in 0..<mirror.count {
        block(mirror[i].0, mirror[i].1.value)
    }
}

И вуаля!

let tuple = ((false, true), 42, 42.195, "42.195km")
iterate(tuple) { println("\($0) => \($1)") }
iterate(tuple.0){ println("\($0) => \($1)")}
iterate(tuple.0.0) { println("\($0) => \($1)")} // no-op

Обратите внимание, что последний не является кортежем, поэтому ничего не происходит (хотя это 1-кортеж или "Single", доступ к которому может быть доступен .0, reflect(it).count равен 0).

Интересно, что iterate() может выполнять итерацию даже других типов коллекций.

iterate([0,1])              { println("\($0) => \($1)") }
iterate(["zero":0,"one":1]) { println("\($0) => \($1)") }

И эта коллекция включает class и struct!

struct Point { var x = 0.0, y = 0.0 }
class  Rect  { var tl = Point(), br = Point() }
iterate(Point()) { println("\($0) => \($1)") }
iterate(Rect())  { println("\($0) => \($1)") }

Предостережение: значение, переданное в качестве второго аргумента блока, относится к типу Any. Вы должны вернуть его к значениям с оригинальным типом.

Ответ 2

В настоящее время Swift не поддерживает итерацию над кортежами.

Самые большие причины:

  • Во время выполнения нет способа определить количество элементов в кортеже
  • Невозможно получить доступ к элементу с определенным индексом, за исключением тех, кто ищет время компиляции, например tupleList.0. Вам действительно нужен индекс tupleList[0], но это нам не предоставляется

Честно говоря, я не вижу причины, по которой вы бы использовали кортеж вместо Array, если хотите перебрать его.

Не имеет смысла перебирать кортеж, потому что:

  • Кортежи всегда имеют фиксированную длину, и каждый элемент имеет фиксированный тип
  • Вы можете назвать каждый член кортежа именем, которое вы можете использовать для доступа к нему позже

Массивы хорошо сделаны для перебора:

  • Произвольная длина
  • Может хранить несколько типов с использованием обычного суперкласса или AnyObject
  • Может быть объявлен как литерал аналогично кортежам: var list = ["A",2.9,3,8,5,6,7,8,9]

Ответ 3

@dankogai отличное решение, обновлено для Swift 3.0:

func iterate<Tuple>(_ tuple:Tuple, body:(_ label:String?,_ value:Any)->Void) {
    for child in Mirror(reflecting: tuple).children {
        body(child.label, child.value)
    }
}

Использование остается идентичным примерам @dankogai (за исключением Swift 2 println()print() rename).

Обратите внимание, что метка теперь имеет тип String?, когда она ранее была String, чтобы соответствовать изменению типа от Swift 1 MirrorType.subscript(…).0 до Swift 3 Mirror.Child.label. Тем не менее, для наборов с нечеткой привязкой аргумент label возвращается как ".0", ".1", ".2" и т.д. - это только nil для некоторых других типов.

Кроме того, я взял на себя смелость переименовать типы и аргументы, чтобы лучше совместить Swift 3 упрощенные стандарты именования и изменить закрытие возвращаемый тип до Void.

Sidenote: я заметил, что кто-то меня превзошел здесь. Я не могу представить, почему, кроме (справедливого) аргумента, что создание функциональности приложения вокруг отражения в Swift - это взломать систему типов и, вероятно, приведет к дрянной (Swift-кортежи не следует рассматривать как абстрактный тип данных, а скорее небольшую совокупность переменных, аналогичную аргументам метода). Как контраргумент, я изначально закончил переносить это на Swift 3 в проекте, потому что мне это нужно - для лучшего description и debugDescription s. Потому что разумный вывод отладки позволит вам сэкономить часы и часы разочарования.;-) Кроме того, это может быть действительно полезно для модульных тестов... потому что тесты в конечном итоге больше всего интересуются "сделал ли результат этой операции то, что мы ожидаем?"

Ответ 4

Нет, вы не можете. Причина в том, что элементы кортежа не все должны иметь один и тот же тип, поэтому вы не сможете узнать, какой тип each должен иметь.