2015-06-23 4 views
0

Я хотел бы использовать более функциональное программирование в Swift. Некоторые из функций, которые я пишу, могут хорошо работать на массивах различных типов. Я не хочу переписывать одну и ту же функцию с разными типами (или typealiases.) Шаблон, как работает функция, часто одинаков, как раз с разными типами. Таким образом, я пытался что-то вроде этого:Функции на общих массивах

// Add indeces to an array of any type. I.e., returns an array of tuples of the array index and the original element. 
func addIndeces<T: AnyObject>(toArray: Array<T>) -> Array<(index: Int, value: T)> { 
    var arrIndex: [Int] = [] 
    for index in 0...toArray.count { 
     arrIndex.append(index) 
    } 
    return Array(Zip2(arrIndex, toArray)) 
} 

Когда я называю эту функцию

// Note: reminderList is of type [Reminder] 
let indexedReminderList = addIndeces(reminderList) as! [(index: Int, reminder: Reminder)] 

я получаю ошибку во время выполнения: «неустранимая ошибка: не может unsafeBitCast между типами различных размеров»

Что я делаю неправильно?

+0

Я скопировал свой код, но я не получаю сообщение об ошибке выполнения. Вместо этого возникает ошибка compiletime, где говорится, что я должен измениться как! как. Можете ли вы объяснить, почему вы вообще делаете свой результат? Одно замечание: вы можете просто вернуть Array (Zip2 (Array (0 .. Qbyte

+0

@Qbyte или даже 'Array (zip (индексы (toArray), toArray))' или (работает только с целые индексированные коллекции) 'Array (enumerate (toArray))' –

+0

Спасибо за оптимизацию. Я использовал их. Однако проблема все еще существует. Он должен быть «как!'иначе вы получите эту ошибку:' Array <(index: Int, value: Reminder)> 'не конвертируется в' [(index: Int, напоминание: напоминание)] '; вы хотели использовать «как!» заставить downcast? – Daniel

ответ

1

Вы хотите бросить кортеж Array типа [(index: Int, value: T)] где T имеет тип Reminder к кортежу Array типа [(index: Int, reminder: Reminder)]. Таким образом, вы можете видеть, что кортежи имеют разные имена элементов (значение и напоминание), где оба имеют разные размеры байтов - поэтому ошибка.

Итак, вы должны взять те же имена элементов для обоих кортежей.

Если вы хотите изменить имена элементов:

let newTupleArray = oldTupleArray.map{ (newElementName0: $0.0, newElementName1: $0.1) } 
0

Диапазон 0...toArray.count состоит из всех элементов формы 0 в счетчике toArray, включая значение счета, а в вашем случае arrIndex всегда будет иметь еще один элемент, затем toArray. То, что вызывает ошибку разного размера. Чтобы исправить это, замените свой диапазон на этот 0..<toArray.count

+1

Я не думаю, что «размер» связан с размером массива, а не с фактическим размером байта типа. – Qbyte

+0

Это не проблема. – Daniel

+0

@Qbyte Напоминает класс или структуру? –

2

Функция, которую вы пишете, уже существует - вид. enumerate "возвращает ленивая SequenceType содержащих пары (п, х), где п \ S являются последовательными Int \ S, начиная с нулем, и х \ S являются элементами base"

Этих означает, что вы можете написать функцию:

func addIndices<T>(toArray: [T]) -> [(index: Int, reminder: T)] { 

    // if you want to label the tuple elements index: and reminder:, 
    // you still have to use map: 
    return map(enumerate(toArray)) { 
     (index: $0, reminder: $1) 
    } 

} 

Обратите внимание, что вам не нужно писать T: AnyObject если вы специально покупки чтобы эта функция не принимала ничего, кроме массивов классов (так как это AnyObject - это протокол, который соответствует только классам, а не структурам или перечислениям).

Примечание: enumerate работает только для целых индексированных коллекций. Чтобы сделать его более общим, вы можете написать zip(indices(someCollection),someCollection)). indices возвращает диапазон всех индексов любой коллекции, что эквивалентно someCollection.startIndex..<someCollection.endIndex.

Смежные вопросы