Kotlin Bootcamp for Programmers 5.2: Generics

Bu codelab, Kotlin Bootcamp for Programmers kursunun bir parçasıdır. Bu kurstan en iyi şekilde yararlanmak için codelab'leri sırayla tamamlamanızı öneririz. Bilgi düzeyinize bağlı olarak bazı bölümleri gözden geçirebilirsiniz. Bu kurs, nesne yönelimli bir dil bilen ve Kotlin'i öğrenmek isteyen programcılara yöneliktir.

Giriş

Bu codelab'de, genel sınıflar, işlevler ve yöntemler ile bunların Kotlin'deki işleyiş şekli tanıtılmaktadır.

Bu kurstaki dersler, tek bir örnek uygulama oluşturmak yerine bilginizi artırmak için tasarlanmıştır ancak birbirlerinden yarı bağımsız oldukları için aşina olduğunuz bölümleri gözden geçirebilirsiniz. Örneklerin çoğu, bunları bir araya getirmek için akvaryum temasını kullanır. Akvaryumun hikayesinin tamamını görmek isterseniz Kotlin Bootcamp for Programmers (Programcılar için Kotlin Temel Eğitim Programı) adlı Udacity kursuna göz atın.

Bilmeniz gerekenler

  • Kotlin işlevlerinin, sınıflarının ve yöntemlerinin söz dizimi
  • IntelliJ IDEA'da yeni bir sınıf oluşturma ve program çalıştırma

Neler öğreneceksiniz?

  • Jenerik sınıflar, yöntemler ve işlevlerle çalışma

Yapacaklarınız

  • Genel sınıf oluşturma ve kısıtlama ekleme
  • in ve out türleri oluşturma
  • Genel işlevler, yöntemler ve uzantı işlevleri oluşturma

Jeneriklere giriş

Kotlin, birçok programlama dili gibi genel türlere sahiptir. Genel tür, bir sınıfı genel hale getirmenize ve böylece sınıfı çok daha esnek hale getirmenize olanak tanır.

Öğelerin listesini tutan bir MyList sınıfı uyguladığınızı düşünün. Jenerikler olmadan, her tür için MyList öğesinin yeni bir sürümünü uygulamanız gerekir: Double için bir sürüm, String için bir sürüm ve Fish için bir sürüm. Genel türler ile listeyi genel hale getirebilirsiniz. Böylece liste, herhangi bir nesne türünü barındırabilir. Bu, türü birçok türe uyacak bir joker karakter haline getirmeye benzer.

Genel bir tür tanımlamak için sınıf adından sonra T'yi açılı ayraçlar <T> içine yerleştirin. (Başka bir harf veya daha uzun bir ad kullanabilirsiniz ancak genel tür için kural T'dir.)

class MyList<T> {
    fun get(pos: Int): T {
        TODO("implement")
    }
    fun addItem(item: T) {}
}

T öğesine normal bir tür gibi referans verebilirsiniz. get() için dönüş türü T, addItem() parametresi ise T türündedir. Elbette, genel listeler çok kullanışlıdır. Bu nedenle List sınıfı Kotlin'e yerleştirilmiştir.

1. adım: Tür hiyerarşisi oluşturun

Bu adımda, sonraki adımda kullanacağınız bazı sınıflar oluşturursunuz. Alt sınıflar önceki bir codelab'de ele alınmıştı ancak burada kısa bir özet sunulmaktadır.

  1. Örneği karmaşık hale getirmemek için src altında yeni bir paket oluşturun ve bu paketi generics olarak adlandırın.
  2. generics paketinde yeni bir Aquarium.kt dosyası oluşturun. Bu sayede, aynı adları kullanarak çakışma olmadan yeniden tanımlama yapabilirsiniz. Bu nedenle, bu codelab'in kodunuzun geri kalanı bu dosyaya girer.
  3. Su kaynağı türlerinin bir tür hiyerarşisini oluşturun. Alt sınıflara ayrılabilmesi için WaterSupply sınıfını open sınıfı yaparak başlayın.
  4. Bir boolean var parametresi needsProcessing ekleyin. Bu işlem, getter ve setter ile birlikte otomatik olarak değiştirilebilir bir özellik oluşturur.
  5. WaterSupply sınıfını genişleten bir TapWater alt sınıfı oluşturun ve musluk suyunda balıklar için zararlı olan katkı maddeleri bulunduğundan needsProcessing için true değerini iletin.
  6. TapWater içinde, suyu temizledikten sonra needsProcessing değerini false olarak ayarlayan addChemicalCleaners() adlı bir işlev tanımlayın. needsProcessing özelliği, varsayılan olarak public olduğu ve alt sınıflar tarafından erişilebildiği için TapWater konumundan ayarlanabilir. Tamamlanmış kodu aşağıda bulabilirsiniz.
package generics

open class WaterSupply(var needsProcessing: Boolean)

class TapWater : WaterSupply(true) {
   fun addChemicalCleaners() {
       needsProcessing = false
   }
}
  1. WaterSupply sınıfının FishStoreWater ve LakeWater adlı iki alt sınıfını daha oluşturun. FishStoreWater işlenmesi gerekmez ancak LakeWater, filter() yöntemiyle filtrelenmelidir. Filtreleme işleminden sonra tekrar işlenmesi gerekmez. Bu nedenle filter() içinde needsProcessing = false olarak ayarlayın.
class FishStoreWater : WaterSupply(false)

class LakeWater : WaterSupply(true) {
   fun filter() {
       needsProcessing = false
   }
}

Daha fazla bilgiye ihtiyacınız varsa Kotlin'de devralma ile ilgili önceki derse göz atın.

2. adım: Genel bir sınıf oluşturun

Bu adımda, farklı su kaynaklarını desteklemek için Aquarium sınıfını değiştirirsiniz.

  1. Aquarium.kt dosyasında, sınıf adından sonra köşeli parantez içinde <T> ile birlikte bir Aquarium sınıfı tanımlayın.
  2. Aquarium öğesine T türünde değişmez bir özellik waterSupply ekleyin.
class Aquarium<T>(val waterSupply: T)
  1. genericsExample() adlı bir işlev yazın. Bu, bir sınıfın parçası olmadığından dosyanın en üst düzeyinde yer alabilir (ör. main() işlevi veya sınıf tanımları). İşlevde bir Aquarium oluşturun ve ona bir WaterSupply iletin. waterSupply parametresi genel olduğundan türü köşeli parantez içinde <> belirtmeniz gerekir.
fun genericsExample() {
    val aquarium = Aquarium<TapWater>(TapWater())
}
  1. genericsExample() kodunuzla akvaryumun waterSupply bölümüne erişebilirsiniz. TapWater türünde olduğundan, addChemicalCleaners() işlevini tür dönüşümü olmadan çağırabilirsiniz.
fun genericsExample() {
    val aquarium = Aquarium<TapWater>(TapWater())
    aquarium.waterSupply.addChemicalCleaners()
}
  1. Aquarium nesnesini oluştururken Kotlin'de tür çıkarımı olduğundan köşeli parantezleri ve aralarındaki içeriği kaldırabilirsiniz. Bu nedenle, örneği oluştururken TapWater ifadesini iki kez kullanmanıza gerek yoktur. Tür, Aquarium bağımsız değişkeninden çıkarılabilir. Bu durumda, türü TapWater olan bir Aquarium oluşturulur.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    aquarium.waterSupply.addChemicalCleaners()
}
  1. Ne olduğunu görmek için addChemicalCleaners() işlevini çağırmadan önce ve sonra needsProcessing işlevini yazdırın. Tamamlanmış işlevi aşağıda görebilirsiniz.
fun genericsExample() {
    val aquarium = Aquarium<TapWater>(TapWater())
    println("water needs processing: ${aquarium.waterSupply.needsProcessing}")
    aquarium.waterSupply.addChemicalCleaners()
    println("water needs processing: ${aquarium.waterSupply.needsProcessing}")
}
  1. main() işlevi ekleyerek genericsExample() işlevini çağırın, ardından programınızı çalıştırıp sonucu gözlemleyin.
fun main() {
    genericsExample()
}
⇒ water needs processing: true
water needs processing: false

3. adım: Daha spesifik hale getirin

Genel (Generic), neredeyse her şeyi iletebileceğiniz anlamına gelir ve bu bazen sorunlara yol açabilir. Bu adımda, Aquarium sınıfına ne koyabileceğiniz konusunda daha spesifik olursunuz.

  1. genericsExample() içinde Aquarium oluşturun, waterSupply için bir dize iletin ve akvaryumun waterSupply özelliğini yazdırın.
fun genericsExample() {
    val aquarium2 = Aquarium("string")
    println(aquarium2.waterSupply)
}
  1. Programınızı çalıştırın ve sonucu gözlemleyin.
⇒ string

Aquarium, T. üzerinde herhangi bir sınırlama getirmediği için sonuç, ilettiğiniz dizedir. String dahil olmak üzere herhangi bir tür iletilebilir.

  1. genericsExample() içinde, waterSupply için null değerini ileterek başka bir Aquarium oluşturun. waterSupply değeri null ise "waterSupply is null" yazdırılır.
fun genericsExample() {
    val aquarium3 = Aquarium(null)
    if (aquarium3.waterSupply == null) {
        println("waterSupply is null")
    }
}
  1. Programınızı çalıştırın ve sonucu gözlemleyin.
⇒ waterSupply is null

Neden Aquarium oluştururken null iletebilirsiniz? Bunun nedeni, varsayılan olarak T'nın, tür hiyerarşisinin en üstündeki tür olan null değer atanabilir Any? türünü temsil etmesidir. Aşağıdaki ifade, daha önce yazdığınız ifadeye eşdeğerdir.

class Aquarium<T: Any?>(val waterSupply: T)
  1. null değerinin iletilmesine izin vermemek için Any türünde T oluşturun. Bunu, Any değerinden sonraki ? değerini kaldırarak yapabilirsiniz.
class Aquarium<T: Any>(val waterSupply: T)

Bu bağlamda, Any öğesine genel kısıtlama adı verilir. Bu, T için null olmadığı sürece herhangi bir türün iletilebileceği anlamına gelir.

  1. Aslında istediğiniz, T için yalnızca WaterSupply (veya alt sınıflarından biri) iletilebilmesini sağlamaktır. Daha spesifik bir genel kısıtlama tanımlamak için Any yerine WaterSupply kullanın.
class Aquarium<T: WaterSupply>(val waterSupply: T)

4. adım: Daha fazla kontrol ekleyin

Bu adımda, kodunuzun beklendiği gibi çalıştığından emin olmanıza yardımcı olacak check() işlevi hakkında bilgi edineceksiniz. check() işlevi, Kotlin'deki standart bir kitaplık işlevidir. Bu işlev, bir onaylama işlevi görür ve bağımsız değişkeni false olarak değerlendirilirse IllegalStateException hatası verir.

  1. Suyu önceden işlemenize gerek kalmaması için addWater() sınıfına Aquarium yöntemi ekleyerek check() ile su ekleyin.
class Aquarium<T: WaterSupply>(val waterSupply: T) {
    fun addWater() {
        check(!waterSupply.needsProcessing) { "water supply needs processing first" }
        println("adding water from $waterSupply")
    }    
}

Bu durumda, needsProcessing doğruysa check() istisna oluşturur.

  1. genericsExample() içinde LakeWater ile Aquarium oluşturmak için kod ekleyin ve ardından biraz su ekleyin.
fun genericsExample() {
    val aquarium4 = Aquarium(LakeWater())
    aquarium4.addWater()
}
  1. Programınızı çalıştırdığınızda, suyun önce filtrelenmesi gerektiğinden bir istisna alırsınız.
⇒ Exception in thread "main" java.lang.IllegalStateException: water supply needs processing first
        at Aquarium.generics.Aquarium.addWater(Aquarium.kt:21)
  1. Aquarium'ya eklemeden önce suyu filtrelemek için bir arama ekleyin. Artık programınızı çalıştırdığınızda istisna oluşmaz.
fun genericsExample() {
    val aquarium4 = Aquarium(LakeWater())
    aquarium4.waterSupply.filter()
    aquarium4.addWater()
}
⇒ adding water from generics.LakeWater@880ec60

Yukarıda, jeneriklerin temelleri açıklanmıştır. Aşağıdaki görevlerde daha fazla bilgi verilmektedir ancak önemli olan, genel kısıtlaması olan genel bir sınıfın nasıl bildirileceği ve kullanılacağıdır.

Bu görevde, jeneriklerle in ve out türleri hakkında bilgi edineceksiniz. in türü, yalnızca bir sınıfa geçirilebilen, döndürülemeyen bir türdür. out türü, yalnızca bir sınıftan döndürülebilen bir türdür.

Aquarium sınıfına baktığınızda, genel türün yalnızca waterSupply özelliği alınırken döndürüldüğünü görürsünüz. T türünde bir değeri parametre olarak alan herhangi bir yöntem yoktur (yapıcıda tanımlama hariç). Kotlin, tam olarak bu durum için out türleri tanımlamanıza olanak tanır ve türlerin nerede güvenle kullanılabileceği hakkında ek bilgiler çıkarabilir. Benzer şekilde, yalnızca yöntemlere geçirilen ancak hiçbir zaman döndürülmeyen genel türler için in türleri tanımlayabilirsiniz. Bu sayede Kotlin, kod güvenliği için ek kontroller yapabilir.

in ve out türleri, Kotlin'in tür sistemi için yönergelerdir. Tüm tür sistemini açıklamak bu yoğun eğitimin kapsamı dışındadır (oldukça karmaşık bir konudur). Ancak derleyici, in ve out ile uygun şekilde işaretlenmemiş türleri işaretler. Bu nedenle, bu türler hakkında bilgi sahibi olmanız gerekir.

1. adım: Bir çıkış türü tanımlayın

  1. Aquarium sınıfında T: WaterSupply değerini out türü olarak değiştirin.
class Aquarium<out T: WaterSupply>(val waterSupply: T) {
    ...
}
  1. Aynı dosyada, sınıfın dışında, addItemTo() işlevini WaterSupply türünde bir Aquarium bekleyecek şekilde tanımlayın.
fun addItemTo(aquarium: Aquarium<WaterSupply>) = println("item added")
  1. genericsExample()'den addItemTo()'yı arayın ve programınızı çalıştırın.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    addItemTo(aquarium)
}
⇒ item added

Kotlin, addItemTo() türünde güvenli olmayan hiçbir işlem yapmayacağını garanti edebilir. Bunun nedeni, addItemTo()'nın out türünde bildirilmiş olmasıdır.WaterSupply

  1. out anahtar kelimesini kaldırırsanız derleyici, addItemTo() çağrılırken hata verir. Bunun nedeni, Kotlin'in türle ilgili güvenli olmayan bir işlem yapmadığınızı garanti edememesidir.

2. adım: Bir "in" türü tanımlayın

in türü, out türüne benzer ancak yalnızca işlevlere geçirilen, döndürülmeyen genel türler içindir. in türü döndürmeye çalışırsanız derleyici hatası alırsınız. Bu örnekte, bir arayüzün parçası olarak in türünü tanımlayacaksınız.

  1. Aquarium.kt dosyasında, WaterSupply ile sınırlanmış genel bir T alan Cleaner arayüzü tanımlayın. Yalnızca clean() için bağımsız değişken olarak kullanıldığından bunu in parametresi yapabilirsiniz.
interface Cleaner<in T: WaterSupply> {
    fun clean(waterSupply: T)
}
  1. Cleaner arayüzünü kullanmak için kimyasal madde ekleyerek TapWater temizleme işlemi için Cleaner uygulayan bir sınıf TapWaterCleaner oluşturun.
class TapWaterCleaner : Cleaner<TapWater> {
    override fun clean(waterSupply: TapWater) =   waterSupply.addChemicalCleaners()
}
  1. Aquarium sınıfında, addWater() türünde bir Cleaner almak için addWater() öğesini güncelleyin ve eklemeden önce suyu temizleyin.T
class Aquarium<out T: WaterSupply>(val waterSupply: T) {
    fun addWater(cleaner: Cleaner<T>) {
        if (waterSupply.needsProcessing) {
            cleaner.clean(waterSupply)
        }
        println("water added")
    }
}
  1. genericsExample() örnek kodunu TapWaterCleaner, TapWater ile Aquarium oluşturacak şekilde güncelleyin ve temizleyiciyi kullanarak biraz su ekleyin. Temizleyiciyi gerektiğinde kullanır.
fun genericsExample() {
    val cleaner = TapWaterCleaner()
    val aquarium = Aquarium(TapWater())
    aquarium.addWater(cleaner)
}

Kotlin, kodunuzda jeneriklerin güvenli bir şekilde kullanıldığından emin olmak için in ve out türü bilgilerini kullanır. Out ve in kolayca hatırlanabilir: out türleri, dönüş değerleri olarak dışarıya aktarılabilir, in türleri ise bağımsız değişkenler olarak içeriye aktarılabilir.

Türlerdeki ve tür dışındaki sorunların çözümüyle ilgili daha fazla bilgi edinmek isterseniz dokümanlarda bu konular ayrıntılı olarak ele alınır.

Bu görevde, genel işlevler ve bunların ne zaman kullanılacağı hakkında bilgi edineceksiniz. Genellikle, işlevin genel türü olan bir sınıfın bağımsız değişkenini alması durumunda genel bir işlev oluşturmak iyi bir fikirdir.

1. adım: Genel bir işlev oluşturun

  1. generics/Aquarium.kt dosyasında, Aquarium alan bir isWaterClean() işlevi oluşturun. Parametrenin genel türünü belirtmeniz gerekir. Bir seçenek olarak WaterSupply kullanabilirsiniz.
fun isWaterClean(aquarium: Aquarium<WaterSupply>) {
   println("aquarium water is clean: ${aquarium.waterSupply.needsProcessing}")
}

Ancak bu, Aquarium öğesinin çağrılabilmesi için out türünde bir parametreye sahip olması gerektiği anlamına gelir. Bazen hem giriş hem de çıkış için bir tür kullanmanız gerektiğinden out veya in çok kısıtlayıcı olabilir. İşlevi genel hale getirerek out şartını kaldırabilirsiniz.

  1. İşlevi genel hale getirmek için anahtar kelimeden fun sonra genel bir tür T ve kısıtlamalarla birlikte köşeli parantezleri ekleyin. Bu örnekte kısıtlama WaterSupply'dır. Aquarium değerinin WaterSupply yerine T ile sınırlandırılmasını sağlayın.
fun <T: WaterSupply> isWaterClean(aquarium: Aquarium<T>) {
   println("aquarium water is clean: ${!aquarium.waterSupply.needsProcessing}")
}

T, akvaryumun genel türünü belirtmek için kullanılan isWaterClean() türü parametresidir. Bu kalıp çok yaygındır ve üzerinde biraz çalışmak iyi bir fikirdir.

  1. İşlev adından hemen sonra ve parantezlerden önce türü köşeli parantez içinde belirterek isWaterClean() işlevini çağırın.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    isWaterClean<TapWater>(aquarium)
}
  1. aquarium bağımsız değişkeninden tür çıkarımı yapıldığından tür gerekli değildir. Bu nedenle, türü kaldırın. Programınızı çalıştırın ve çıktıyı inceleyin.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    isWaterClean(aquarium)
}
⇒ aquarium water is clean: false

2. adım: Somutlaştırılmış tür içeren genel bir yöntem oluşturun

Kendi genel türüne sahip sınıflarda bile yöntemler için genel işlevler kullanabilirsiniz. Bu adımda, Aquarium türünde olup olmadığını kontrol eden genel bir yöntem ekliyorsunuz.WaterSupply

  1. Aquarium sınıfında, WaterSupply ile sınırlı olan ve genel bir parametre R (T zaten kullanılıyor) alan ve waterSupply, R türündeyse true döndüren bir yöntem hasWaterSupplyOfType() tanımlayın. Bu, daha önce tanımladığınız işleve benzer ancak Aquarium sınıfının içindedir.
fun <R: WaterSupply> hasWaterSupplyOfType() = waterSupply is R
  1. Son R karakterinin kırmızı renkte altı çizili olduğuna dikkat edin. Hatanın ne olduğunu görmek için işaretçiyi üzerine getirin.
  2. is kontrolü yapmak için Kotlin'e türün reified (gerçek) olduğunu ve işlevde kullanılabileceğini söylemeniz gerekir. Bunu yapmak için inline anahtar kelimesinin önüne fun, genel türün R önüne ise reified koyun.
inline fun <reified R: WaterSupply> hasWaterSupplyOfType() = waterSupply is R

Bir tür somutlaştırıldıktan sonra, satır içi hale getirildiği için gerçek bir tür olarak normal bir tür gibi kullanabilirsiniz. Yani türü kullanarak is kontrolü yapabilirsiniz.

Burada reified kullanmazsanız tür, Kotlin'in is kontrollerine izin vereceği kadar "gerçek" olmaz. Bunun nedeni, somutlaştırılmamış türlerin yalnızca derleme zamanında kullanılabilmesi ve programınız tarafından çalışma zamanında kullanılamamasıdır. Bu konu, bir sonraki bölümde daha ayrıntılı olarak ele alınmıştır.

  1. Tür olarak TapWater değerini iletin. Genel işlevleri çağırmak gibi, işlev adından sonra türü köşeli parantez içinde kullanarak genel yöntemleri çağırın. Programınızı çalıştırın ve sonucu gözlemleyin.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    println(aquarium.hasWaterSupplyOfType<TapWater>())   // true
}
⇒ true

3. adım: Uzantı işlevleri oluşturun

Somutlaştırılmış türleri normal işlevler ve uzantı işlevleri için de kullanabilirsiniz.

  1. Aquarium sınıfının dışında, WaterSupply üzerinde isOfType() adlı bir uzantı işlevi tanımlayın. Bu işlev, iletilen WaterSupply öğesinin belirli bir türde olup olmadığını (ör. TapWater) kontrol eder.
inline fun <reified T: WaterSupply> WaterSupply.isOfType() = this is T
  1. Uzantı işlevini tıpkı bir yöntem gibi çağırın.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    println(aquarium.waterSupply.isOfType<TapWater>())  
}
⇒ true

Bu uzantı işlevleriyle, Aquarium olduğu sürece türünün (Aquarium veya TowerTank ya da başka bir alt sınıf) önemi yoktur.Aquarium Yıldız projeksiyonu söz dizimini kullanmak, çeşitli eşleşmeleri belirtmenin kolay bir yoludur. Kotlin, yıldız projeksiyonu kullandığınızda da güvenli olmayan bir işlem yapmadığınızdan emin olur.

  1. Yıldız projeksiyonu kullanmak için <*> simgesini Aquarium simgesinden sonra yerleştirin. hasWaterSupplyOfType(), Aquarium'nin temel API'sinin bir parçası olmadığı için uzantı işlevi olarak taşınır.
inline fun <reified R: WaterSupply> Aquarium<*>.hasWaterSupplyOfType() = waterSupply is R
  1. Çağrıyı hasWaterSupplyOfType() olarak değiştirin ve programınızı çalıştırın.
fun genericsExample() {
    val aquarium = Aquarium(TapWater())
    println(aquarium.hasWaterSupplyOfType<TapWater>())
}
⇒ true

Önceki örnekte, Kotlin'in bunları yalnızca derleme zamanında değil, çalışma zamanında da bilmesi gerektiğinden genel türü reified olarak işaretlemeniz ve işlevi inline yapmanız gerekiyordu.

Tüm genel türler yalnızca derleme sırasında Kotlin tarafından kullanılır. Bu sayede derleyici, her şeyi güvenli bir şekilde yaptığınızdan emin olabilir. Çalışma zamanında tüm genel türler silinir. Bu nedenle, silinmiş bir türün kontrol edilmesiyle ilgili hata mesajı daha önce gösterilmişti.

Derleyicinin, genel türleri çalışma zamanına kadar tutmadan doğru kodu oluşturabildiği anlaşılıyor. Ancak bu, bazen derleyicinin destekleyemediği is gibi genel türlerde kontroller yapabileceğiniz anlamına gelir. Bu nedenle Kotlin, reified (gerçek) türleri ekledi.

Somutlaştırılmış türler ve tür silme hakkında daha fazla bilgiyi Kotlin dokümanlarında bulabilirsiniz.

Bu derste, kodu daha esnek ve yeniden kullanmayı kolaylaştırmak için önemli olan jeneriklere odaklanıldı.

  • Kodu daha esnek hale getirmek için genel sınıflar oluşturun.
  • Genel türlerle kullanılan türleri sınırlamak için genel kısıtlamalar ekleyin.
  • Sınıflara iletilen veya sınıflardan döndürülen türleri kısıtlamak için daha iyi tür kontrolü sağlamak üzere jeneriklerle in ve out türlerini kullanın.
  • Genel türlerle çalışmak için genel işlevler ve yöntemler oluşturun. Örneğin:
    fun <T: WaterSupply> isWaterClean(aquarium: Aquarium<T>) { ... }
  • Bir sınıfa temel olmayan işlevler eklemek için genel uzantı işlevlerini kullanın.
  • Tür silme nedeniyle bazen somutlaştırılmış türler gerekir. Gerçekleştirilmiş türler, genel türlerin aksine çalışma zamanına kadar devam eder.
  • Kodunuzun beklendiği gibi çalıştığını doğrulamak için check() işlevini kullanın. Örneğin:
    check(!waterSupply.needsProcessing) { "water supply needs processing first" }

Kotlin belgeleri

Bu kurstaki herhangi bir konu hakkında daha fazla bilgi edinmek veya takıldığınız noktaları aşmak için https://kotlinlang.org adresini ziyaret edebilirsiniz.

Kotlin eğitimleri

https://try.kotlinlang.org web sitesinde Kotlin Koans adlı zengin eğitimler, web tabanlı bir yorumlayıcı ve örneklerle birlikte eksiksiz bir referans dokümanı seti yer alır.

Udacity kursu

Bu konuyla ilgili Udacity kursunu görüntülemek için Kotlin Bootcamp for Programmers'a (Programcılar için Kotlin Temel Eğitimi) göz atın.

IntelliJ IDEA

IntelliJ IDEA ile ilgili dokümanları JetBrains web sitesinde bulabilirsiniz.

Bu bölümde, bir eğitmenin yönettiği kurs kapsamında bu codelab'i tamamlayan öğrenciler için olası ödevler listelenmektedir. Eğitmen, aşağıdakileri yapmalıdır:

  • Gerekirse ödev atayın.
  • Öğrencilere ev ödevi ödevlerini nasıl göndereceklerini bildirin.
  • Ödevlere not verin.

Eğitmenler bu önerileri istedikleri kadar kullanabilir ve uygun olduğunu düşündükleri diğer ödevleri verebilirler.

Bu codelab'i kendi başınıza tamamlıyorsanız bilginizi test etmek için bu ödevleri kullanabilirsiniz.

Bu soruları yanıtlayın.

1. Soru

Aşağıdakilerden hangisi genel bir türü adlandırma kuralıdır?

<Gen>

<Generic>

<T>

<X>

2. Soru

Genel bir tür için izin verilen türlerle ilgili kısıtlamaya ne ad verilir?

▢ genel bir kısıtlama

▢ genel bir kısıtlama

▢ netleştirme

▢ genel tür sınırı

3. Soru

Gerçekleştirilmiş (Reified) şu anlama gelir:

▢ Bir nesnenin gerçek yürütme etkisi hesaplanmıştır.

▢ Sınıfta kısıtlanmış bir giriş dizini ayarlanmışsa

▢ Genel tür parametresi gerçek bir tür haline getirildi.

▢ Uzak hata göstergesi tetiklendi.

Sonraki derse geçin: 6. İşlevsel manipülasyon

Diğer codelab'lerin bağlantıları da dahil olmak üzere kursa genel bir bakış için "Kotlin Bootcamp for Programmers: Welcome to the course." başlıklı makaleyi inceleyin.