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 kod laboratuvarında, Kotlin'deki çiftler, koleksiyonlar ve uzantı işlevleri gibi çeşitli faydalı özelliklerle tanışacaksınız.
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 Kotlin'in REPL'si (Read-Eval-Print Loop) ile çalışma
- IntelliJ IDEA'da yeni bir sınıf oluşturma ve program çalıştırma
Neler öğreneceksiniz?
- İkili ve üçlü öğelerle çalışma
- Koleksiyonlar hakkında daha fazla bilgi
- Sabitleri tanımlama ve kullanma
- Uzantı işlevleri yazma
Yapacaklarınız
- REPL'de çiftler, üçlüler ve karma haritalar hakkında bilgi
- Sabitleri düzenlemenin farklı yollarını öğrenin
- Uzantı işlevi ve uzantı özelliği yazma
Bu görevde, çiftler ve üçlüler hakkında bilgi edinecek ve bunları yapılarını bozmayı öğreneceksiniz. Çiftler ve üçlüler, 2 veya 3 genel öğe için önceden hazırlanmış veri sınıflarıdır. Bu, örneğin bir işlevin birden fazla değer döndürmesi için yararlı olabilir.
List
balığınız olduğunu ve balığın tatlı su balığı mı yoksa tuzlu su balığı mı olduğunu kontrol eden bir isFreshWater()
işleviniz olduğunu varsayalım. List.partition()
, biri durumun true
olduğu öğeleri, diğeri ise durumun false
olduğu öğeleri içeren iki liste döndürür.
val twoLists = fish.partition { isFreshWater(it) }
println("freshwater: ${twoLists.first}")
println("saltwater: ${twoLists.second}")
1. adım: İkili ve üçlü gruplar oluşturun
- REPL'yi açın (Araçlar > Kotlin > Kotlin REPL).
- Bir ekipmanı ne için kullanıldığıyla ilişkilendirerek bir çift oluşturun ve değerleri yazdırın. İki değeri (ör. iki dize)
to
anahtar kelimesiyle bağlayan bir ifade oluşturarak çift oluşturabilir, ardından her bir değere başvurmak için.first
veya.second
kullanabilirsiniz.
val equipment = "fish net" to "catching fish"
println("${equipment.first} used for ${equipment.second}")
⇒ fish net used for catching fish
toString()
ile üçlü oluşturup yazdırın, ardındantoList()
ile listeye dönüştürün.Triple()
kullanarak 3 değer içeren bir üçlü oluşturursunuz. Her bir değere atıfta bulunmak için.first
,.second
ve.third
özelliklerini kullanın.
val numbers = Triple(6, 9, 42)
println(numbers.toString())
println(numbers.toList())
⇒ (6, 9, 42) [6, 9, 42]
Yukarıdaki örneklerde, çiftin veya üçlünün tüm parçaları için aynı tür kullanılmaktadır ancak bu zorunlu değildir. Parçalar; dize, sayı veya liste olabilir. Örneğin, başka bir çift ya da üçlü.
- Çiftin ilk bölümünün kendisi de çift olan bir çift oluşturun.
val equipment2 = ("fish net" to "catching fish") to "equipment"
println("${equipment2.first} is ${equipment2.second}\n")
println("${equipment2.first.second}")
⇒ (fish net, catching fish) is equipment ⇒ catching fish
2. adım: Bazı ikili ve üçlü grupları ayrıştırın
Çiftleri ve üçlüleri bileşenlerine ayırmaya yapı bozma denir. Çifti veya üçlüyü uygun sayıda değişkene atayın. Kotlin, her bölümün değerini sırayla atar.
- Bir çifti yapıdan çıkarma ve değerleri yazdırma.
val equipment = "fish net" to "catching fish"
val (tool, use) = equipment
println("$tool is used for $use")
⇒ fish net is used for catching fish
- Üçlü bir yapıyı bozup değerleri yazdırın.
val numbers = Triple(6, 9, 42)
val (n1, n2, n3) = numbers
println("$n1 $n2 $n3")
⇒ 6 9 42
Çiftlerin ve üçlülerin yapılarını bozmanın, önceki bir codelab'de ele alınan veri sınıflarıyla aynı şekilde çalıştığını unutmayın.
Bu görevde, listeler de dahil olmak üzere koleksiyonlar ve yeni bir koleksiyon türü olan karma eşlemler hakkında daha fazla bilgi edineceksiniz.
1. adım: Listeler hakkında daha fazla bilgi edinin
- Listeler ve değiştirilebilir listeler önceki bir derste tanıtılmıştı. Çok kullanışlı bir veri yapısı olduklarından Kotlin, listeler için bir dizi yerleşik işlev sağlar. Listeler için bu kısmi işlev listesini inceleyin. Tam listeleri
List
veMutableList
ile ilgili Kotlin belgelerinde bulabilirsiniz.
İşlev | Purpose |
| Değiştirilebilir listeye öğe ekleyin. |
| Değiştirilebilir bir listeden öğe kaldırma. |
| Öğelerin ters sırada olduğu listenin bir kopyasını döndürür. |
| Liste öğeyi içeriyorsa |
| Listenin bir bölümünü döndürür. Bu bölüm, ilk dizinden başlayıp ikinci dizine kadar (ikinci dizin hariç) olan kısmı kapsar. |
- REPL'de çalışmaya devam ederek bir sayı listesi oluşturun ve bu listede
sum()
işlevini çağırın. Bu, tüm öğelerin toplamıdır.
val list = listOf(1, 5, 3, 4)
println(list.sum())
⇒ 13
- Dizelerden oluşan bir liste oluşturun ve listeyi toplayın.
val list2 = listOf("a", "bbb", "cc")
println(list2.sum())
⇒ error: none of the following functions can be called with the arguments supplied:
- Öğe,
List
öğesinin doğrudan nasıl toplayacağını bilmediği bir şeyse (ör. dize),.sumBy()
ile bir lambda işlevi kullanarak nasıl toplanacağını belirtebilirsiniz. Örneğin, her dizenin uzunluğuna göre toplama işlemi yapabilirsiniz. Lambda bağımsız değişkeninin varsayılan adıit
'dır. Buradait
, liste üzerinde gezinilirken listenin her bir öğesini ifade eder.
val list2 = listOf("a", "bbb", "cc")
println(list2.sumBy { it.length })
⇒ 6
- Listelerle yapabileceğiniz daha birçok şey var. Kullanılabilir işlevleri görmenin bir yolu, IntelliJ IDEA'da bir liste oluşturup noktayı ekledikten sonra ipucundaki otomatik tamamlama listesine bakmaktır. Bu yöntem, tüm nesneler için geçerlidir. Bu özelliği bir listede deneyin.
- Listeden
listIterator()
simgesini seçin, ardındanfor
ifadesiyle listeyi inceleyin ve boşluklarla ayrılmış tüm öğeleri yazdırın.
val list2 = listOf("a", "bbb", "cc")
for (s in list2.listIterator()) {
println("$s ")
}
⇒ a bbb cc
2. adım: Karma haritaları deneyin
Kotlin'de hashMapOf()
kullanarak neredeyse her şeyi başka bir şeye eşleyebilirsiniz. Karma haritalar, ilk değerin anahtar olarak kullanıldığı bir çift listesine benzer.
- Balıkların semptomlarını (anahtarlar) ve hastalıklarını (değerler) eşleştiren bir karma eşlem oluşturun.
val cures = hashMapOf("white spots" to "Ich", "red sores" to "hole disease")
- Ardından,
get()
veya daha kısa olan köşeli parantezleri[]
kullanarak hastalık değerini belirti anahtarına göre alabilirsiniz.
println(cures.get("white spots"))
⇒ Ich
println(cures["red sores"])
⇒ hole disease
- Haritada bulunmayan bir belirti belirtmeyi deneyin.
println(cures["scale loss"])
⇒ null
Bir anahtar haritada yoksa eşleşen hastalığı döndürmeye çalışmak null
değerini döndürür. Harita verilerine bağlı olarak, olası bir anahtar için eşleşme olmaması yaygın bir durumdur. Bu gibi durumlarda Kotlin, getOrDefault()
işlevini sağlar.
getOrDefault()
kullanarak eşleşmesi olmayan bir anahtarı aramayı deneyin.
println(cures.getOrDefault("bloating", "sorry, I don't know"))
⇒ sorry, I don't know
Yalnızca değer döndürmekten daha fazlasını yapmanız gerekiyorsa Kotlin, getOrElse()
işlevini sağlar.
- Kodunuzu
getOrDefault()
yerinegetOrElse()
kullanacak şekilde değiştirin.
println(cures.getOrElse("bloating") {"No cure for this"})
⇒ No cure for this
Basit bir varsayılan değer döndürmek yerine, küme parantezleri {}
arasındaki kod yürütülür. Örnekte else
yalnızca bir dize döndürür ancak bu, tedavi yöntemi içeren bir web sayfası bulup döndürmek kadar karmaşık da olabilir.
mutableListOf
gibi, mutableMapOf
da oluşturabilirsiniz. Değiştirilebilir bir harita, öğe yerleştirmenize ve kaldırmanıza olanak tanır. Değişebilir (mutable) yalnızca değişebilir anlamına gelirken değişmez (immutable) değişemez anlamına gelir.
- Bir ekipman dizesini öğe sayısıyla eşleyerek değiştirilebilen bir envanter haritası oluşturun. Akvaryumun içine balık ağı koyarak oluşturun, ardından
put()
ile envantere 3 akvaryum temizleyici ekleyin veremove()
ile balık ağını kaldırın.
val inventory = mutableMapOf("fish net" to 1)
inventory.put("tank scrubber", 3)
println(inventory.toString())
inventory.remove("fish net")
println(inventory.toString())
⇒ {fish net=1, tank scrubber=3}{tank scrubber=3}
Bu görevde, Kotlin'deki sabitler ve bunları düzenlemenin farklı yolları hakkında bilgi edineceksiniz.
1. adım: const ve val hakkında bilgi edinin
- REPL'de sayısal bir sabit oluşturmayı deneyin. Kotlin'de,
const val
kullanarak üst düzey sabitler oluşturabilir ve derleme zamanında bunlara değer atayabilirsiniz.
const val rocks = 3
Değer atanır ve değiştirilemez. Bu, normal bir val
bildirmeye çok benzer. Peki const val
ile val
arasındaki fark nedir? const val
değeri derleme zamanında belirlenirken val
değeri program yürütme sırasında belirlenir. Bu nedenle, val
çalışma zamanında bir işlev tarafından atanabilir.
Bu, val
'ya bir işlevden değer atanabileceği ancak const val
'ye değer atanamayacağı anlamına gelir.
val value1 = complexFunctionCall() // OK
const val CONSTANT1 = complexFunctionCall() // NOT ok
Ayrıca, const val
yalnızca üst düzeyde ve object
ile tanımlanan tekil sınıflarda çalışır, normal sınıflarda çalışmaz. Bu özelliği kullanarak yalnızca sabitleri içeren bir dosya veya tekil nesne oluşturabilir ve bunları gerektiğinde içe aktarabilirsiniz.
object Constants {
const val CONSTANT2 = "object constant"
}
val foo = Constants.CONSTANT2
2. adım: Yardımcı nesne oluşturun
Kotlin'de sınıf düzeyinde sabitler kavramı yoktur.
Bir sınıfın içinde sabitler tanımlamak için bunları companion
anahtar kelimesiyle tanımlanan tamamlayıcı nesnelere sarmalamanız gerekir. Yardımcı nesne, temelde sınıf içindeki tekil bir nesnedir.
- Dize sabiti içeren bir yardımcı nesneyle sınıf oluşturun.
class MyClass {
companion object {
const val CONSTANT3 = "constant in companion"
}
}
Yardımcı nesneler ile normal nesneler arasındaki temel fark şudur:
- Companion nesneler, kapsayan sınıfın statik oluşturucusundan başlatılır. Yani nesne oluşturulduğunda oluşturulurlar.
- Normal nesneler, bu nesneye ilk erişimde (yani ilk kullanıldıklarında) geç başlatılır.
Daha fazla bilgi var ancak şu an için bilmeniz gereken tek şey, sabitleri bir yardımcı nesnedeki sınıflara sarmalamaktır.
Bu görevde, sınıfların davranışını genişletme hakkında bilgi edineceksiniz. Bir sınıfın davranışını genişletmek için yardımcı işlevler yazmak çok yaygındır. Kotlin, bu yardımcı işlevleri (uzantı işlevleri) bildirmek için uygun bir söz dizimi sağlar.
Uzantı işlevleri, kaynak koduna erişmek zorunda kalmadan mevcut bir sınıfa işlev eklemenize olanak tanır. Örneğin, bunları paketinizin bir parçası olan Extensions.kt dosyasında bildirebilirsiniz. Bu, sınıfı gerçekten değiştirmez ancak bu sınıfın nesnelerinde işlevi çağırırken nokta gösterimini kullanmanıza olanak tanır.
1. adım: Uzantı işlevi yazın
- REPL'de çalışmaya devam ederek bir dizenin boşluk içerip içermediğini kontrol etmek için basit bir uzantı işlevi
hasSpaces()
yazın. İşlev adının önüne üzerinde çalıştığı sınıf eklenir. İşlevin içindethis
, üzerinde çağrıldığı nesneyi,it
isefind()
çağrısındaki yineleyiciyi ifade eder.
fun String.hasSpaces(): Boolean {
val found = this.find { it == ' ' }
return found != null
}
println("Does it have spaces?".hasSpaces())
⇒ true
hasSpaces()
işlevini basitleştirebilirsiniz.this
açıkça gerekli değildir ve işlev tek bir ifadeye indirgenip döndürülebilir. Bu nedenle, etrafındaki küme parantezleri{}
de gerekli değildir.
fun String.hasSpaces() = find { it == ' ' } != null
2. adım: Uzantıların sınırlamalarını öğrenin
Uzantı işlevleri yalnızca genişlettikleri sınıfın herkese açık API'sine erişebilir. private
olan değişkenlere erişilemez.
private
olarak işaretlenmiş bir özelliğe uzantı işlevleri eklemeyi deneyin.
class AquariumPlant(val color: String, private val size: Int)
fun AquariumPlant.isRed() = color == "red" // OK
fun AquariumPlant.isBig() = size > 50 // gives error
⇒ error: cannot access 'size': it is private in 'AquariumPlant'
- Aşağıdaki kodu inceleyin ve ne yazdıracağını bulun.
open class AquariumPlant(val color: String, private val size: Int)
class GreenLeafyPlant(size: Int) : AquariumPlant("green", size)
fun AquariumPlant.print() = println("AquariumPlant")
fun GreenLeafyPlant.print() = println("GreenLeafyPlant")
val plant = GreenLeafyPlant(size = 10)
plant.print()
println("\n")
val aquariumPlant: AquariumPlant = plant
aquariumPlant.print() // what will it print?
⇒ GreenLeafyPlant AquariumPlant
plant.print()
baskı GreenLeafyPlant
. aquariumPlant.print()
değişkenine plant
değeri atandığı için aquariumPlant.print()
değişkeninin de GreenLeafyPlant
değerini yazdırmasını bekleyebilirsiniz. Ancak tür, derleme zamanında çözümlendiği için AquariumPlant
yazdırılır.
3. adım: Uzantı özelliği ekleyin
Kotlin, uzantı işlevlerine ek olarak uzantı özellikleri de eklemenize olanak tanır. Uzantı işlevlerinde olduğu gibi, genişlettiğiniz sınıfı, ardından bir nokta ve ardından özellik adını belirtirsiniz.
- REPL'de çalışmaya devam ederek
isGreen
uzantı özelliğiniAquariumPlant
öğesine ekleyin. Bu özellik, renk yeşilsetrue
olur.
val AquariumPlant.isGreen: Boolean
get() = color == "green"
isGreen
özelliğine normal bir özellik gibi erişilebilir. Erişildiğinde, değeri almak için isGreen
getter'ı çağrılır.
aquariumPlant
değişkeni içinisGreen
özelliğini yazdırın ve sonucu inceleyin.
aquariumPlant.isGreen
⇒ res4: kotlin.Boolean = true
4. adım: Nullable alıcılar hakkında bilgi edinin
Genişlettiğiniz sınıfa alıcı adı verilir ve bu sınıfı null yapılabilir hale getirmek mümkündür. Bu durumda, gövdede kullanılan this
değişkeni null
olabilir. Bu nedenle, bu durumu test ettiğinizden emin olun. Arayanların, uzantı yönteminizi null değer atanabilir değişkenlerde çağırmak isteyeceğini düşünüyorsanız veya işleviniz null
için uygulandığında varsayılan bir davranış sağlamak istiyorsanız null değer atanabilir bir alıcı kullanmak isteyebilirsiniz.
- REPL'de çalışmaya devam ederken, null değer atanabilir bir alıcı alan
pull()
yöntemi tanımlayın. Bu, türden sonra ve noktadan önce soru işareti?
ile belirtilir. Gövde içinde, soru işareti-nokta-uygula?.apply.
kullanarakthis
öğesininnull
olmadığını test edebilirsiniz.
fun AquariumPlant?.pull() {
this?.apply {
println("removing $this")
}
}
val plant: AquariumPlant? = null
plant.pull()
- Bu durumda, programı çalıştırdığınızda çıkış olmaz.
plant
,null
olduğu için içtekiprintln()
çağrılmaz.
Uzantı işlevleri çok güçlüdür ve Kotlin standart kitaplığının çoğu uzantı işlevi olarak uygulanır.
Bu derste koleksiyonlar ve sabitler hakkında daha fazla bilgi edindiniz. Ayrıca, uzantı işlevlerinin ve özelliklerinin gücünü keşfettiniz.
- Çiftler ve üçlüler, bir işlevden birden fazla değer döndürmek için kullanılabilir. Örneğin:
val twoLists = fish.partition { isFreshWater(it) }
- Kotlin,
List
içinreversed()
,contains()
vesubList()
gibi birçok yararlı işleve sahiptir. - Anahtarları değerlerle eşlemek için
HashMap
kullanılabilir. Örneğin:val cures = hashMapOf("white spots" to "Ich", "red sores" to "hole disease")
const
anahtar kelimesini kullanarak derleme zamanı sabitlerini bildirin. Bunları en üst düzeye yerleştirebilir, tekil bir nesnede düzenleyebilir veya yardımcı bir nesneye yerleştirebilirsiniz.- Companion object,
companion
anahtar kelimesiyle tanımlanan bir sınıf tanımı içindeki tekil bir nesnedir. - Uzantı işlevleri ve özellikleri, bir sınıfa işlevsellik ekleyebilir. Örneğin:
fun String.hasSpaces() = find { it == ' ' } != null
- Null olabilen alıcı,
null
olabilen bir sınıfta uzantılar oluşturmanıza olanak tanır.?.
operatörü, kodu yürütmeden öncenull
olup olmadığını kontrol etmek içinapply
ile birlikte kullanılabilir. Örneğin:this?.apply { println("removing $this") }
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.
Pair
Triple
List
MutableList
HashMap
- Tamamlayıcı nesneler
- Uzantılar
- Boş değer atanabilir alıcı (Nullable receiver)
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 bir listenin kopyasını döndürür?
▢ add()
▢ remove()
▢ reversed()
▢ contains()
2. Soru
class AquariumPlant(val color: String, val size: Int, private val cost: Double, val leafy: Boolean)
üzerindeki aşağıdaki uzantı işlevlerinden hangisi derleyici hatası verir?
▢ fun AquariumPlant.isRed() = color == "red"
▢ fun AquariumPlant.isBig() = size > 45
▢ fun AquariumPlant.isExpensive() = cost > 10.00
▢ fun AquariumPlant.isNotLeafy() = leafy == false
3. Soru
Aşağıdakilerden hangisi, const val
ile sabitleri tanımlayabileceğiniz bir yer değildir?
▢ Bir dosyanın en üst düzeyinde
▢ normal sınıflarda
▢ tekil nesnelerde
▢ Tamamlayıcı nesnelerde
Sonraki derse geçin:
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.