Множественные ограничения типов в Swift

Скажем, у меня есть эти протоколы:

protocol SomeProtocol {

}

protocol SomeOtherProtocol {

}

Теперь, если мне нужна функция, которая принимает общий тип, но этот тип должен соответствовать SomeProtocol, я мог бы сделать:

func someFunc<T: SomeProtocol>(arg: T) {
    // do stuff
}

Но есть ли способ добавить ограничение типа для нескольких протоколов?

func bothFunc<T: SomeProtocol | SomeOtherProtocol>(arg: T) {

}

Аналогичные вещи используют запятые, но в этом случае он начнет объявление другого типа. Вот что я пробовал.

<T: SomeProtocol | SomeOtherProtocol>
<T: SomeProtocol , SomeOtherProtocol>
<T: SomeProtocol : SomeOtherProtocol>

Ответ 1

Вы можете использовать where where, который позволяет указать столько требований, сколько вы хотите (все это должно быть выполнено), разделенные запятыми

Swift 2:

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
    // stuff
}

Swift 3 и 4:

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    // stuff
}

или более мощное предложение where:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
    // stuff
}

Вы можете, конечно, использовать состав протокола (например, protocol<SomeProtocol, SomeOtherProtocol>), но он немного менее гибкий.

Использование where позволяет обрабатывать случаи, когда задействованы несколько типов.

Вы все равно можете составлять протоколы для повторного использования в нескольких местах или просто предоставить составленному протоколу значащее имя.

Ответ 2

У вас есть две возможности:

  • Вы используете где предложение, как указано в ответе Jiaaro:

    func someFunc<T where T : SomeProtocol, T : SomeOtherProtocol>(arg: T) {
        // do stuff
    }
    
  • Вы используете

Ответ 3

В эволюцию Swift 3.0 внесены некоторые изменения. Теперь наши два варианта выглядят немного иначе.

Использование предложения where в Swift 3.0:

Предложение where теперь перемещено в конец сигнатуры функции для улучшения удобочитаемости. Таким образом, наследование нескольких протоколов теперь выглядит следующим образом:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol {

}

Использование конструкции protocol<> в Swift 3.0:

Композиция, использующая конструкцию protocol<>, устарела. Раньше protocol<SomeProtocol, SomeOtherProtocol> теперь выглядит следующим образом:

func someFunc<T:SomeProtocol & SomeOtherProtocol>(arg: T) {

}

Ссылки.

Дополнительная информация об изменениях для where находится здесь: https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

И больше об изменениях для конструкции протокола < > приведены здесь: https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md

Ответ 4

Swift 3 предлагает до 3 различных способов объявить вашу функцию.

protocol SomeProtocol {
    /* ... */
}

protocol SomeOtherProtocol {
    /* ... */        
}

1. Используя оператор &

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    /* ... */
}

2. Используя предложение where

func someFunc<T>(arg: T) where T: SomeProtocol, T: SomeOtherProtocol {
    /* ... */
}

3. Используя оператор where и & оператор

func someFunc<T>(arg: T) where T: SomeProtocol & SomeOtherProtocol {
    /* ... */        
}

Также обратите внимание, что вы можете использовать typealias, чтобы сократить объявление функции.

typealias RequiredProtocols = SomeProtocol & SomeOtherProtocol

func someFunc<T: RequiredProtocols>(arg: T) {
    /* ... */   
}