Ответ
Да, с помощью ассоциированных типов (associatedtype). Они определяют требования к типу, который будет указан при реализации протокола.
Базовый пример:
protocol Container {
associatedtype Element
var items: [Element] { get set }
mutating func add(_ item: Element)
}
struct IntContainer: Container {
// Явное указание типа (можно опустить, Swift выведет)
typealias Element = Int
var items: [Int] = []
mutating func add(_ item: Int) {
items.append(item)
}
}
// Использование с автоматическим выводом типа
struct StringContainer: Container {
var items: [String] = []
mutating func add(_ item: String) { items.append(item) }
}
Протокол с ограничениями на тип:
protocol ComparableContainer {
associatedtype Item: Comparable // Ограничение
func contains(_ item: Item) -> Bool
}
Ключевые отличия от дженерик-классов:
- Протоколы используют
associatedtype, классы/структуры —<T>в объявлении. - Ассоциированные типы более гибкие: конкретный тип определяется в реализации, а не при использовании протокола.
- Это позволяет создавать коллекции разных типов, реализующих один протокол (например,
[Container]), где каждый элемент может иметь свойElement.