Swift Generics: Başlangıç

Generics, Swift’in çok güçlü yanlarından biridir. Başlangıçta anlaması kolay olmasa da ve çok değişik kullanımları olsa da özellikle kod tekrarını önlemek, Framework veya SDK yazarken genele hitap edebilmek açısından kullanımı oldukça önem arz etmektedir.

Generics in Functions

Bazı fonksiyonlar birçok tipe hitap etmesi amacıyla yazılırlar. Örneğin hem Int hem de Double değerler arasında toplama işlemi olabilir. Eskiden bunu fonksiyon overload ile yapıyorduk ve temelde aynı kodu tekrar etmiş oluyorduk.

Örneğin elimizdeki dizinin ilk elemanını dönecek olan bir fonksiyon yazdığımızı düşünelim. İlk aşamada elimizde bir Int dizisi olsun ve buna uygun bir fonksiyon yazalım.

Proje ilerledikten sonra şimdi de bir String dizisinin ilk elemanını bize dönen bir fonksiyona ihtiyaç duyduğumuzu düşünelim. Bu kez fonksiyonumuzu aşağıdaki hale getirecektik.

Bu durum proje ilerledikçe, ihtiyaçlar ortaya çıktıkça böyle sürüp gidecekti.  Fakat Generics kullanarak bunun önüne geçmemiz mümkün. Fonksiyon tanımında herhangi bir tip belirtmek yerine Generic ifade kullanıp, fonksiyonumuzu tüm tiplere açık hale getirebiliriz.

Burada fonksiyon tanımlarken “< >” ifadeleri arasına yazdığımız yalnızca bir label’dır. Bu label derleme anında asıl türü olarak davranmaya başlayacaktır.

Yukarıdaki şekilde iki dizi oluşturup fonksiyonumuzu çağırırsak aşağıdaki gibi bir sonuç elde ederiz.

Kendi oluşturduğumuz bir Struct’ı da bu fonksiyon içerisinde kullanabiliriz.

Generics Constraining

Kullanmak istediğimiz Generic yapıların belirli kurallara uymasını veya belirli protokolleri karşılamasını isteyebiliriz. Bu durumda generic tipimizin hangi kurala uymasını istediğimizi constraint kullanarak belirtebiliriz.

Örneğin bir dizi içerisindeki minimum değeri elde etmek için fonksiyon yazdığımızı düşünelim. Bu durumda minimum elemanı bulmak için karşılaştırma işlemleri yapmak zorundayız. Yani bizim tanımladığımız generic tip “Karşılaştırılabilir” olmak zorundadır.

Yukarıdaki fonksiyonumuzun tanımında <T: Comparable> ifadesini kullanarak generic tipimizin karşılaştırılabilir olmasını kısıt olarak sunduk.

Bu durumda kendi oluşturduğumuz Struct için de “Comparable” şartını yerine getirmemiz gerekiyor. Bu işlemi bir extension yazarak gerçekleştirelim.

Protocol: Associated Type

Protocol’lerin içerisinde de generic tipler kullanabiliriz. Aşağıdaki gibi bir protokol yazdığımızı düşünelim.

Protokol bir adet “Weapon” label’ı ile belirtilmiş generic tipe sahip ve bunu kendisine uyması beklenen tüm sınıflara aktaracak, aynı zamanda gerektiğinde bu tipi bize sunacak bir adet de fonksiyonu mevcut.

Şimdi de protokolümüze uymasını istediğimiz bir sınıf yazalım.

Görüldüğü gibi Pokemon adında bir sınıf tanımladık ve bu sınıfın Attacker protokolüne uymasını istedik. Böylece sınıfımızın bir adet Weapon generic tipinde property’si ve bu property’i bize sunacak olan fonksiyonu oluştu. Şimdi sıra geldi Weapon olarak kullanılabilecek sınıflar yaratmaya.

Şimdi bu tipler için birer adet pokemon oluşturalım.

Görüldüğü gibi her bir pokemon farklı yeteneğe ve silaha sahip oldu. Böylece Pokemon’lar için ayrı ayrı sınıflar oluşturmak yerine protokol ve generics yapılarını kullanarak daha bakımı kolay ve kendisini tekrarlamayan bir kod ürettik.

Bir cevap yazın