Ограничения обобщенного типа в Swift

В качестве упражнения я пытаюсь расширить Array в Swift, чтобы добавить функцию-член sum(). Это должно быть типобезопасно, так как я хочу, чтобы вызов sum() компилировался только в том случае, если массив содержит элементы, которые могут быть добавлены.

Я пробовал несколько вариантов чего-то вроде этого:

extension Array {

    func sum<U : _IntegerArithmeticType where U == T>() -> Int {
        var acc = 0
        for elem in self {
            acc += elem as Int
        }
        return acc
    }

}

Идея заключалась в том, чтобы сказать: «Хорошо, это универсальная функция, универсальный тип должен быть чем-то вроде Int, а также должен быть таким же, как T, тип элементов массива». Но компилятор жалуется: «Требование одинакового типа делает общие параметры U и T эквивалентными». Правильно, так и должно быть, с дополнительным ограничением T : _IntegerArithmeticType.

Почему компилятор не позволяет мне это сделать? Как мне это сделать?

(Я знаю, что позже мне придется исправить, как складываются вещи и какой именно тип возвращаемого значения, но пока я застрял на ограничении типа.)


person Jean-Philippe Pellet    schedule 28.01.2015    source источник
comment
(В настоящее время) невозможно расширить Array методами, требующими, чтобы элементы были ограниченного типа. Сравните stackoverflow.com/questions/ 24938948/ или stackoverflow.com/questions/25630476/ (оба могут считаться дубликатами).   -  person Martin R    schedule 28.01.2015
comment
Вы написали «(в настоящее время)». Кто-нибудь слышал шепот, что это может скоро измениться?   -  person Jean-Philippe Pellet    schedule 28.01.2015
comment
Я думаю, что читал на devforums.apple.com, что это известная проблема и она может измениться в будущем, но я не уверен на 100%. Ссылку дам, если еще раз найду.   -  person Martin R    schedule 28.01.2015
comment
Спасибо. Я опубликую наименее плохой обходной путь, который я нашел, в качестве ответа.   -  person Jean-Philippe Pellet    schedule 28.01.2015


Ответы (1)


Согласно комментарию Мартина Р., в настоящее время это невозможно. В этой конкретной ситуации у меня возникает соблазн использовать явную передачу функции преобразования T -> Int:

extension Array {

    func sum(toInt: T -> Int?) -> Int {
        var acc = 0
        for elem in self {
            if let i = toInt(elem) {
                acc += i
            }
        }
        return acc
    }

}

Тогда я могу написать что-то вроде этого:

func itself<T>(t: T) -> T {
    return t
}

let ss = ["1", "2", "3", "4", "five"].sum { $0.toInt() }
let si = [1, 2, 3, 4].sum(itself)

Однако должна быть передана явная функция. Часть (itself) можно, конечно, заменить на { $0 }. (Другие называют функцию itself identity.)

Обратите внимание, что функция A -> B может быть передана, когда требуется A -> B?.

person Jean-Philippe Pellet    schedule 28.01.2015