Как создать общую функцию для добавляемых параметров?

Работая с дженериками Swift, у меня есть следующий вопрос:

Эта функция работает, как и ожидалось, с типом Int:

func + (number: Int, vector: [Int]) -> [Int] {
    var resArray:[Int]=[]
    for x:Int in vector {
        resArray.append(number+x)
    }
    return resArray
}

Я хочу, чтобы это работало с любым типом, где добавление имеет смысл. Я пробовал следующее:

func +<T:NSNumber> (number: T.Type, vector: [T.Type]) -> [T.Type] {
    var resArray:[T.Type]=[]
    for x:T.Type in vector {
        resArray.append(number+x)
    }
    return resArray
}

Но строчка:

resArray.append(number+x)

сталкивается с проблемой, потому что число и x должны очевидно поддерживать сложение.

Как мне изменить свой код? Я полагаю, мне нужно добавить ограничение на тип. Я не совсем знаю, как.


person Michel    schedule 09.12.2015    source источник


Ответы (1)


Вы можете определить такое ограничение, как вы сказали, как протокол, подобный AdditiveSemigroup ниже.

protocol AdditiveSemigroup {
    typealias Out = Self
    static func + (a: Self, b: Self) -> Out
}

func +<T: AdditiveSemigroup where T.Out == T> (value: T, vector: [T]) -> [T] {
    return vector.map { $0 + value }
}

Чтобы тип соответствовал приведенному выше протоколу, просто определите расширение для этого типа.

extension String: AdditiveSemigroup {}

"A" + ["A", "B", "C"] // ==> ["AA", "AB", "AC"]

Для NSNumber не было встроенного оператора +, поэтому вам нужно определить его вручную.

extension NSNumber: AdditiveSemigroup {
    typealias This = NSNumber
}

func + (a: NSNumber, b: NSNumber) -> NSNumber {
    return NSNumber(double: a.doubleValue + b.doubleValue)
}

Теперь вы можете применить свой специальный оператор + к значениям NSNumber.

NSNumber(double: 3) + [NSNumber(double: 5)] // ==> 8
person findall    schedule 09.12.2015
comment
Мне нравится ваша идея полугруппы, но не имеет смысла определять псевдоним типа Out, поскольку определение полугруппы заключается в том, что операция всегда возвращает Self. Также имя не должно быть Semigroup, поскольку оно специализировано для определенного символа (вместо этого может быть AdditiveSemigroup. Также where T.Out == T не требуется. - person Kametrixom; 09.12.2015
comment
Также static не нужен - person Kametrixom; 09.12.2015
comment
Объявление в протоколе метода, возвращающего Self, приводит к тому, что неокончательный класс (например, NSNumber) не может ему соответствовать. И where T.Out == T - это просто обходной путь для этого.. - person findall; 09.12.2015
comment
Ах, я вижу, тогда это имеет больше смысла - person Kametrixom; 09.12.2015
comment
Спасибо за понимание. И static необходим, потому что встроенный оператор + не является методом, если вы хотите, чтобы тип соответствовал протоколу без переопределения какой-либо функции, как это делает extension String в моем ответе. - person findall; 09.12.2015