Associatedtype ve where kısıtlamalarıyla protokoller, Swift'te tiplerin soyutlanması için güçlü bir mekanizmadır. Bu genellikle belirli türlerin uygulanımına göre belirlendiği genel protokollerin uygulanmasında kullanılır. Tarihsel olarak, Swift'in erken sürümlerinde associatedtype içeren protokoller, somut türler (existential types) olarak kullanılamıyordu, bu da bu tür protokollerin koleksiyonlar ve arayüzlerde kullanımını kısıtlıyordu. Daha sonra Swift, associatedtype için where koşulları kullanarak kısıtlamalar ekleme mekanizmaları ekledi, bu da karmaşık senaryolar için esnek ve güvenli soyutlamalar oluşturmaya olanak tanıdı.
Sorun: Genellikle belirli koleksiyonlardan veya veri işlemcilerinden soyutlanmayı sağlayan bir protokol oluşturma ihtiyacı ortaya çıkar. Ancak standart protokoller yeterince esnek olmayabilir: Tüm türler ilişkili türlerle ilgili bilgi olmadan genelleyici olarak kullanılamaz ve associatedtype ile protokollerin miras alma mantığı her zaman net olmayabilir.
Çözüm: Uygulamalar için gereksinimleri belirlemek amacıyla where-kısıtlamalarını kullanmak, esnek davranışa sahip protokoller oluşturmaya olanak tanır.
Kod örneği:
protocol Storage { associatedtype Element func add(_ item: Element) } // Sadece sayıları depolayan kısıtlı protokol protocol NumericStorage: Storage where Element: Numeric { func sum() -> Element } struct IntStorage: NumericStorage { private var items: [Int] = [] func add(_ item: Int) { items.append(item) } func sum() -> Int { items.reduce(0, +) } }
Ana özellikler:
Associatedtype içeren bir protokolü tipe (örneğin bir koleksiyon için) kullanmak mümkün mü?
Hayır, doğrudan değil. Associatedtype içeren bir protokol, PAT (protocol with associated type) olup, existential type olarak kullanılamaz. Örneğin, [Storage] dizisini tanımlamak mümkün olmaz, yalnızca type erasure yoluyla yapılabilir.
Associatedtype içeren bir protokole type-erasure nasıl uygulanır?
Gerçek tipin uygulanımını gizleyen yardımcı bir sarmalayıcı aracılığıyla.
struct AnyStorage<T>: Storage { private let _add: (T) -> Void init<S: Storage>(_ storage: S) where S.Element == T { _add = storage.add } func add(_ item: T) { _add(item) } }
Associatedtype ile protokolün generic parametresi arasındaki fark nedir?
associatedtype, uygulanması gereken belirli bir tipi tanımlar, ancak generic-parametre, protokol veya işlevde açıkça belirtilir; fakat protokol tanımında kullanılmasına izin verilmez. Protokol, sözdizimi açısından generic olamaz, yalnızca associatedtype aracılığıyla olabilir.
Bir geliştirici, herhangi bir koleksiyonun depolanması için [Storage] kullanmaya çalıştı. Kod derlenmiyor, zorunlu tür dönüşümleri veya Any/unsafe yöntemler kullanmak zorunda kalıyor.
Artılar:
Eksiler:
Bir geliştirici, belirli uygulamayı gizlemek için AnyStorage<T> oluşturdu, sadece gerekli türlerle uygun şekilde çalışmasını sağlamak için where kısıtlamaları ekledi.
Artılar:
Eksiler: