Codelab นี้เป็นส่วนหนึ่งของหลักสูตร Kotlin Bootcamp สำหรับโปรแกรมเมอร์ คุณจะได้รับประโยชน์สูงสุดจากหลักสูตรนี้หากทำตาม Codelab ตามลำดับ คุณอาจข้ามบางส่วนได้ ทั้งนี้ขึ้นอยู่กับความรู้ของคุณ หลักสูตรนี้เหมาะสำหรับโปรแกรมเมอร์ที่รู้จักภาษาเชิงวัตถุและต้องการเรียนรู้ Kotlin
บทนำ
นี่คือโค้ดแล็บสุดท้ายใน Kotlin Bootcamp ในโค้ดแล็บนี้ คุณจะได้เรียนรู้เกี่ยวกับคำอธิบายประกอบและช่วงพักที่มีป้ายกำกับ คุณจะตรวจสอบแลมบ์ดาและฟังก์ชันลำดับสูง ซึ่งเป็นส่วนสำคัญของ Kotlin นอกจากนี้ คุณยังได้เรียนรู้เพิ่มเติมเกี่ยวกับฟังก์ชันอินไลน์และอินเทอร์เฟซ Single Abstract Method (SAM) สุดท้ายนี้ คุณจะได้ดูข้อมูลเพิ่มเติมเกี่ยวกับคลังมาตรฐานของ Kotlin
บทเรียนในหลักสูตรนี้ได้รับการออกแบบมาเพื่อสร้างความรู้ของคุณ แต่จะมีความเป็นอิสระจากกันในระดับหนึ่งเพื่อให้คุณข้ามส่วนที่คุณคุ้นเคยได้ แทนที่จะสร้างแอปตัวอย่างเพียงแอปเดียว ตัวอย่างหลายรายการใช้ธีมตู้ปลาเพื่อเชื่อมโยงตัวอย่างต่างๆ เข้าด้วยกัน และหากต้องการดูเรื่องราวทั้งหมดของตู้ปลา ให้ดูหลักสูตร Kotlin Bootcamp for Programmers ของ Udacity
สิ่งที่คุณควรทราบอยู่แล้ว
- ไวยากรณ์ของฟังก์ชัน คลาส และเมธอด Kotlin
- วิธีสร้างคลาสใหม่ใน IntelliJ IDEA และเรียกใช้โปรแกรม
- ข้อมูลพื้นฐานเกี่ยวกับฟังก์ชันแลมบ์ดาและฟังก์ชันลำดับสูง
สิ่งที่คุณจะได้เรียนรู้
- ข้อมูลเบื้องต้นเกี่ยวกับคำอธิบายประกอบ
- วิธีใช้การแบ่งที่มีป้ายกำกับ
- ข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชันลำดับที่สูงกว่า
- เกี่ยวกับอินเทอร์เฟซ Single Abstract Method (SAM)
- เกี่ยวกับไลบรารีมาตรฐานของ Kotlin
สิ่งที่คุณต้องดำเนินการ
- สร้างคำอธิบายประกอบแบบง่าย
- ใช้การแบ่งที่มีป้ายกำกับ
- ตรวจสอบฟังก์ชัน Lambda ใน Kotlin
- ใช้และสร้างฟังก์ชันลำดับที่สูงกว่า
- เรียกใช้อินเทอร์เฟซ Single Abstract Method บางรายการ
- ใช้ฟังก์ชันบางอย่างจาก Kotlin Standard Library
คำอธิบายประกอบเป็นวิธีแนบข้อมูลเมตาเข้ากับโค้ด และไม่ได้เป็นสิ่งเฉพาะสำหรับ Kotlin โดยคอมไพเลอร์จะอ่านคำอธิบายประกอบและใช้เพื่อสร้างโค้ดหรือตรรกะ เฟรมเวิร์กหลายรายการ เช่น Ktor และ Kotlinx รวมถึง Room ใช้คำอธิบายประกอบเพื่อกำหนดค่าวิธีเรียกใช้และโต้ตอบกับโค้ด คุณไม่น่าจะเห็นคำอธิบายประกอบจนกว่าจะเริ่มใช้เฟรมเวิร์ก แต่การรู้วิธีอ่านคำอธิบายประกอบก็มีประโยชน์
นอกจากนี้ ยังมีคำอธิบายประกอบที่พร้อมใช้งานผ่านไลบรารีมาตรฐานของ Kotlin ซึ่งควบคุมวิธีคอมไพล์โค้ด ซึ่งมีประโยชน์มากหากคุณส่งออกโค้ด Kotlin ไปยังโค้ด Java แต่ในกรณีอื่นๆ คุณไม่จำเป็นต้องใช้บ่อยนัก
คำอธิบายประกอบจะอยู่ก่อนสิ่งที่ใส่คำอธิบายประกอบ และคุณใส่คำอธิบายประกอบได้กับแทบทุกอย่าง ไม่ว่าจะเป็นคลาส ฟังก์ชัน เมธอด หรือแม้แต่โครงสร้างควบคุม คำอธิบายประกอบบางรายการสามารถรับอาร์กิวเมนต์ได้
ตัวอย่างคำอธิบายประกอบมีดังนี้
@file:JvmName("InteropFish")
class InteropFish {
companion object {
@JvmStatic fun interop()
}
}ข้อความนี้ระบุว่าชื่อที่ส่งออกของไฟล์นี้คือ InteropFish พร้อมคำอธิบายประกอบ JvmName โดยคำอธิบายประกอบ JvmName จะรับอาร์กิวเมนต์เป็น "InteropFish" ในออบเจ็กต์คู่ @JvmStatic จะบอกให้ Kotlin สร้าง interop() เป็นฟังก์ชันแบบคงที่ใน InteropFish
นอกจากนี้ คุณยังสร้างคำอธิบายประกอบของคุณเองได้ด้วย แต่ส่วนใหญ่จะมีประโยชน์ในกรณีที่คุณกำลังเขียนไลบรารีที่ต้องการข้อมูลเฉพาะเกี่ยวกับคลาสในรันไทม์ ซึ่งก็คือการสะท้อน
ขั้นตอนที่ 1: สร้างแพ็กเกจและไฟล์ใหม่
- สร้างแพ็กเกจใหม่
exampleในส่วน src - ใน example ให้สร้างไฟล์ Kotlin ใหม่ชื่อ
Annotations.kt
ขั้นตอนที่ 2: สร้างคำอธิบายประกอบของคุณเอง
- ใน
Annotations.ktให้สร้างPlantชั้นเรียนด้วย 2 วิธี ได้แก่trim()และfertilize()
class Plant {
fun trim(){}
fun fertilize(){}
}- สร้างฟังก์ชันที่พิมพ์เมธอดทั้งหมดในคลาส ใช้
::classเพื่อรับข้อมูลเกี่ยวกับคลาสในขณะรันไทม์ ใช้declaredMemberFunctionsเพื่อดูรายการเมธอดของคลาส (หากต้องการเข้าถึงส่วนนี้ คุณต้องนำเข้าkotlin.reflect.full.*)
import kotlin.reflect.full.* // required import
class Plant {
fun trim(){}
fun fertilize(){}
}
fun testAnnotations() {
val classObj = Plant::class
for (m in classObj.declaredMemberFunctions) {
println(m.name)
}
}- สร้าง
main()ฟังก์ชันเพื่อเรียกใช้กิจวัตรการทดสอบ เรียกใช้โปรแกรมและสังเกตเอาต์พุต
fun main() {
testAnnotations()
}⇒ trim fertilize
- สร้างคำอธิบายประกอบอย่างง่าย
ImAPlant
annotation class ImAPlantซึ่งจะไม่มีผลใดๆ นอกเหนือจากการระบุว่ามีการอธิบายประกอบ
- เพิ่มคำอธิบายประกอบหน้า
Plantคลาส
@ImAPlant class Plant{
...
}- เปลี่ยน
testAnnotations()เพื่อพิมพ์คำอธิบายประกอบทั้งหมดของชั้นเรียน ใช้annotationsเพื่อรับคำอธิบายประกอบทั้งหมดของชั้นเรียน เรียกใช้โปรแกรมและสังเกตผลลัพธ์
fun testAnnotations() {
val plantObject = Plant::class
for (a in plantObject.annotations) {
println(a.annotationClass.simpleName)
}
}⇒ ImAPlant
- เปลี่ยน
testAnnotations()เพื่อค้นหาคำอธิบายประกอบImAPlantใช้findAnnotation()เพื่อค้นหาคำอธิบายประกอบที่ต้องการ เรียกใช้โปรแกรมและสังเกตผลลัพธ์
fun testAnnotations() {
val plantObject = Plant::class
val myAnnotationObject = plantObject.findAnnotation<ImAPlant>()
println(myAnnotationObject)
}
⇒ @example.ImAPlant()
ขั้นตอนที่ 3: สร้างคำอธิบายประกอบที่กำหนดเป้าหมาย
คำอธิบายประกอบสามารถกำหนดเป้าหมายไปยัง Getter หรือ Setter ได้ เมื่อมีแล้ว คุณจะใช้ได้โดยมีคำนำหน้าเป็น @get: หรือ @set: ซึ่งมักเกิดขึ้นเมื่อใช้เฟรมเวิร์กที่มีคำอธิบายประกอบ
- ประกาศ 2 คำอธิบายประกอบ ได้แก่
OnGetซึ่งใช้ได้กับตัวรับพร็อพเพอร์ตี้เท่านั้น และOnSetซึ่งใช้ได้กับตัวตั้งค่าพร็อพเพอร์ตี้เท่านั้น ใช้@Target(AnnotationTarger.PROPERTY_GETTER)หรือPROPERTY_SETTERในแต่ละรายการ
annotation class ImAPlant
@Target(AnnotationTarget.PROPERTY_GETTER)
annotation class OnGet
@Target(AnnotationTarget.PROPERTY_SETTER)
annotation class OnSet
@ImAPlant class Plant {
@get:OnGet
val isGrowing: Boolean = true
@set:OnSet
var needsFood: Boolean = false
}Annotation มีประสิทธิภาพมากในการสร้างไลบรารีที่ตรวจสอบสิ่งต่างๆ ทั้งในรันไทม์และบางครั้งในเวลาคอมไพล์ อย่างไรก็ตาม โค้ดแอปพลิเคชันทั่วไปจะใช้เพียงคำอธิบายประกอบที่เฟรมเวิร์กมีให้
Kotlin มีหลายวิธีในการควบคุมโฟลว์ คุณคุ้นเคยกับ return อยู่แล้ว ซึ่งจะส่งคืนจากฟังก์ชันไปยังฟังก์ชันที่ครอบคลุม การใช้ break จะคล้ายกับ return แต่ใช้กับลูป
Kotlin ช่วยให้คุณควบคุมลูปได้มากขึ้นด้วยสิ่งที่เรียกว่าการหยุดที่มีป้ายกำกับ break ที่มีป้ายกำกับจะข้ามไปยังจุดดำเนินการทันทีหลังจากลูปที่มีป้ายกำกับนั้น ซึ่งจะมีประโยชน์อย่างยิ่งเมื่อต้องจัดการกับลูปที่ซ้อนกัน
คุณอาจทำเครื่องหมายนิพจน์ใดก็ได้ใน Kotlin ด้วยป้ายกำกับ ป้ายกำกับมีรูปแบบเป็นตัวระบุตามด้วยเครื่องหมาย @
- ใน
Annotations.ktให้ลองใช้การหยุดที่มีป้ายกำกับโดยการหยุดจากลูปด้านใน
fun labels() {
outerLoop@ for (i in 1..100) {
print("$i ")
for (j in 1..100) {
if (i > 10) break@outerLoop // breaks to outer loop
}
}
}
fun main() {
labels()
}- เรียกใช้โปรแกรมและสังเกตเอาต์พุต
⇒ 1 2 3 4 5 6 7 8 9 10 11
ในทำนองเดียวกัน คุณสามารถใช้ continue ที่ติดป้ายกำกับได้ แทนที่จะออกจากลูปที่มีป้ายกำกับ คำสั่ง continue ที่มีป้ายกำกับจะไปยังการวนซ้ำถัดไปของลูป
แลมบ์ดาคือฟังก์ชันที่ไม่ระบุชื่อ ซึ่งเป็นฟังก์ชันที่ไม่มีชื่อ คุณสามารถกำหนดค่าให้กับตัวแปรและส่งเป็นอาร์กิวเมนต์ไปยังฟังก์ชันและเมธอดได้ ซึ่งมีประโยชน์อย่างยิ่ง
ขั้นตอนที่ 1: สร้าง Lambda อย่างง่าย
- เริ่ม REPL ใน IntelliJ IDEA โดยไปที่Tools > Kotlin > Kotlin REPL
- สร้าง Lambda ที่มีอาร์กิวเมนต์
dirty: Intซึ่งทำการคำนวณโดยหารdirtyด้วย 2 กำหนดฟังก์ชัน Lambda ให้กับตัวแปรwaterFilter
val waterFilter = { dirty: Int -> dirty / 2 }- โทรหา
waterFilterโดยส่งค่า 30
waterFilter(30)⇒ res0: kotlin.Int = 15
ขั้นตอนที่ 2: สร้าง Lambda ตัวกรอง
- สร้างคลาสข้อมูล
Fishที่มีพร็อพเพอร์ตี้nameใน REPL
data class Fish(val name: String)- สร้างรายการ
Fish3 รายการที่มีชื่อว่า Flipper, Moby Dick และ Dory
val myFish = listOf(Fish("Flipper"), Fish("Moby Dick"), Fish("Dory"))- เพิ่มตัวกรองเพื่อตรวจสอบชื่อที่มีตัวอักษร "i"
myFish.filter { it.name.contains("i")}
⇒ res3: kotlin.collections.List<Line_1.Fish> = [Fish(name=Flipper), Fish(name=Moby Dick)]
ในนิพจน์ Lambda it หมายถึงองค์ประกอบรายการปัจจุบัน และระบบจะใช้ตัวกรองกับองค์ประกอบรายการแต่ละรายการตามลำดับ
- ใช้
joinString()กับผลลัพธ์โดยใช้", "เป็นตัวคั่น
myFish.filter { it.name.contains("i")}.joinToString(", ") { it.name }
⇒ res4: kotlin.String = Flipper, Moby Dick
ฟังก์ชัน joinToString() จะสร้างสตริงโดยการรวมชื่อที่กรองแล้ว ซึ่งคั่นด้วยสตริงที่ระบุ ซึ่งเป็นหนึ่งในฟังก์ชันที่มีประโยชน์มากมายที่สร้างขึ้นในไลบรารีมาตรฐานของ Kotlin
การส่งแลมบ์ดาหรือฟังก์ชันอื่นๆ เป็นอาร์กิวเมนต์ไปยังฟังก์ชันจะสร้างฟังก์ชันลำดับสูง ตัวกรองด้านบนเป็นตัวอย่างง่ายๆ ของการดำเนินการนี้ filter() เป็นฟังก์ชัน และคุณส่ง Lambda ให้ฟังก์ชันนี้เพื่อระบุวิธีประมวลผลแต่ละองค์ประกอบของรายการ
การเขียนฟังก์ชันลำดับสูงด้วยแลมบ์ดาของส่วนขยายเป็นส่วนที่ซับซ้อนที่สุดส่วนหนึ่งของภาษา Kotlin การเรียนรู้วิธีเขียนสคริปต์อาจต้องใช้เวลาสักพัก แต่ก็ใช้งานได้สะดวกมาก
ขั้นตอนที่ 1: สร้างชั้นเรียนใหม่
- สร้างไฟล์ Kotlin ใหม่
Fish.ktในแพ็กเกจ example - ใน
Fish.ktให้สร้างคลาสข้อมูลFishที่มีพร็อพเพอร์ตี้ 1 รายการname
data class Fish (var name: String)- สร้างฟังก์ชัน
fishExamples()ในfishExamples()ให้สร้างปลาชื่อ"splashy"โดยใช้ตัวพิมพ์เล็กทั้งหมด
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
}- สร้างฟังก์ชัน
main()ที่เรียกใช้fishExamples()
fun main () {
fishExamples()
}- คอมไพล์และเรียกใช้โปรแกรมโดยคลิกสามเหลี่ยมสีเขียวทางด้านซ้ายของ
main()ยังไม่มีเอาต์พุต
ขั้นตอนที่ 2: ใช้ฟังก์ชันลำดับที่สูงกว่า
ฟังก์ชัน with() ช่วยให้คุณอ้างอิงออบเจ็กต์หรือพร็อพเพอร์ตี้อย่างน้อย 1 รายการได้ในรูปแบบที่กะทัดรัดยิ่งขึ้น ใช้ this with() เป็นฟังก์ชันลำดับที่สูงกว่า และใน Lambda คุณจะระบุสิ่งที่ต้องทำกับออบเจ็กต์ที่ระบุ
- ใช้
with()เพื่อเขียนชื่อปลาเป็นตัวพิมพ์ใหญ่ในfishExamples()ภายในเครื่องหมายปีกกาthisหมายถึงออบเจ็กต์ที่ส่งไปยังwith()
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
with (fish.name) {
this.capitalize()
}
}- ไม่มีเอาต์พุต ดังนั้นให้เพิ่ม
println()รอบๆ และthisเป็นแบบโดยนัยและไม่จำเป็น คุณจึงนำออกได้
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
with (fish.name) {
println(capitalize())
}
}⇒ Splashy
ขั้นตอนที่ 3: สร้างฟังก์ชันลำดับสูง
with() เป็นฟังก์ชันลำดับสูง หากต้องการดูวิธีการทำงานนี้ คุณสามารถสร้างเวอร์ชันที่เรียบง่ายของ with() ที่ใช้ได้กับสตริงเท่านั้น
- ใน
Fish.ktให้กำหนดฟังก์ชันmyWith()ที่รับอาร์กิวเมนต์ 2 รายการ อาร์กิวเมนต์คือออบเจ็กต์ที่จะดำเนินการ และฟังก์ชันที่กำหนดการดำเนินการ รูปแบบสำหรับชื่ออาร์กิวเมนต์ที่มีฟังก์ชันคือblockในกรณีนี้ ฟังก์ชันดังกล่าวจะไม่แสดงผลใดๆ ซึ่งระบุด้วยUnit
fun myWith(name: String, block: String.() -> Unit) {}ตอนนี้ block() เป็นฟังก์ชันส่วนขยายของ String ใน myWith() แล้ว โดยมักเรียกคลาสที่ขยายว่าออบเจ็กต์ตัวรับ ดังนั้น name จึงเป็นออบเจ็กต์ผู้รับในกรณีนี้
- ในส่วนเนื้อหาของ
myWith()ให้ใช้ฟังก์ชันblock()ที่ส่งเข้ามากับออบเจ็กต์ตัวรับname
fun myWith(name: String, block: String.() -> Unit) {
name.block()
}- ใน
fishExamples()ให้แทนที่with()ด้วยmyWith()
fun fishExamples() {
val fish = Fish("splashy") // all lowercase
myWith (fish.name) {
println(capitalize())
}
}fish.name คืออาร์กิวเมนต์ชื่อ และ println(capitalize()) คือฟังก์ชันบล็อก
- เรียกใช้โปรแกรม แล้วโปรแกรมจะทำงานเหมือนเดิม
⇒ Splashy
ขั้นตอนที่ 4: สำรวจส่วนขยายอื่นๆ ที่มีอยู่
with() Lambda ของส่วนขยายมีประโยชน์มากและเป็นส่วนหนึ่งของไลบรารีมาตรฐานของ Kotlin และยังมีอีกหลายอย่างที่คุณอาจพบว่ามีประโยชน์ เช่น run(), apply() และ let()
ฟังก์ชัน run() เป็นส่วนขยายที่ใช้ได้กับทุกประเภท โดยจะรับ lambda เป็นอาร์กิวเมนต์ 1 รายการและแสดงผลลัพธ์ของการเรียกใช้ lambda
- ใน
fishExamples()โทรหาrun()ในวันที่fishเพื่อขอชื่อ
fish.run {
name
}ซึ่งจะแสดงผลเฉพาะพร็อพเพอร์ตี้ name คุณสามารถกำหนดค่าดังกล่าวให้กับตัวแปรหรือพิมพ์ได้ ตัวอย่างนี้ไม่ได้มีประโยชน์มากนัก เนื่องจากคุณสามารถเข้าถึงพร็อพเพอร์ตี้ได้โดยตรง แต่ run() อาจมีประโยชน์สำหรับนิพจน์ที่ซับซ้อนกว่า
ฟังก์ชัน apply() คล้ายกับ run() แต่จะแสดงผลออบเจ็กต์ที่เปลี่ยนแปลงซึ่งใช้กับฟังก์ชันดังกล่าวแทนที่จะเป็นผลลัพธ์ของ Lambda ซึ่งอาจเป็นประโยชน์สำหรับการเรียกใช้เมธอดในออบเจ็กต์ที่สร้างขึ้นใหม่
- ทำสำเนาของ
fishและเรียกใช้apply()เพื่อตั้งชื่อสำเนาใหม่
val fish2 = Fish(name = "splashy").apply {
name = "sharky"
}
println(fish2.name)
⇒ sharky
ฟังก์ชัน let() คล้ายกับ apply() แต่จะแสดงผลสำเนาของออบเจ็กต์ที่มีการเปลี่ยนแปลง ซึ่งอาจมีประโยชน์ในการเชื่อมโยงการปรับแต่งเข้าด้วยกัน
- ใช้
let()เพื่อรับชื่อของfish, ทำให้เป็นตัวพิมพ์ใหญ่, ต่อสตริงอื่นเข้ากับสตริงนั้น, รับความยาวของผลลัพธ์นั้น, เพิ่ม 31 ลงในความยาว แล้วพิมพ์ผลลัพธ์
println(fish.let { it.name.capitalize()}
.let{it + "fish"}
.let{it.length}
.let{it + 31})⇒ 42
ในตัวอย่างนี้ ประเภทออบเจ็กต์ที่ it อ้างอิงคือ Fish จากนั้นคือ String แล้วก็ String อีกครั้ง และสุดท้ายคือ Int
- พิมพ์
fishหลังจากเรียกใช้let()แล้วคุณจะเห็นว่าค่าไม่เปลี่ยนแปลง
println(fish.let { it.name.capitalize()}
.let{it + "fish"}
.let{it.length}
.let{it + 31})
println(fish)⇒ 42 Fish(name=splashy)
Lambda และฟังก์ชันลำดับสูงมีประโยชน์มาก แต่คุณควรทราบว่า Lambda คือออบเจ็กต์ นิพจน์ Lambda เป็นอินสแตนซ์ของอินเทอร์เฟซ Function ซึ่งเป็นชนิดย่อยของ Object ลองดูตัวอย่าง myWith() ก่อนหน้านี้
myWith(fish.name) {
capitalize()
}Function อินเทอร์เฟซมีเมธอด invoke() ซึ่งจะมีการลบล้างเพื่อเรียกนิพจน์ Lambda หากเขียนเป็นคำพูดแบบยาวๆ จะมีลักษณะคล้ายกับโค้ดด้านล่าง
// actually creates an object that looks like this
myWith(fish.name, object : Function1<String, Unit> {
override fun invoke(name: String) {
name.capitalize()
}
})โดยปกติแล้วการดำเนินการนี้จะไม่เป็นปัญหา เนื่องจากไม่จำเป็นต้องใช้ทรัพยากรมากนักในการสร้างออบเจ็กต์และเรียกใช้ฟังก์ชัน ซึ่งหมายถึงหน่วยความจำและเวลา CPU แต่หากคุณกําลังกําหนดค่าอย่างเช่น myWith() ที่คุณใช้ทุกที่ ค่าใช้จ่ายอาจเพิ่มขึ้น
Kotlin มี inline เป็นวิธีจัดการกรณีนี้เพื่อลดค่าใช้จ่ายในช่วงรันไทม์โดยเพิ่มงานอีกเล็กน้อยให้กับคอมไพเลอร์ (คุณได้เรียนรู้เกี่ยวกับ inline มาบ้างแล้วในบทเรียนก่อนหน้านี้ที่พูดถึงประเภทที่ทำให้เป็นจริง) การทำเครื่องหมายฟังก์ชันเป็น inline หมายความว่าทุกครั้งที่มีการเรียกใช้ฟังก์ชัน คอมไพเลอร์จะแปลงซอร์สโค้ดเป็น "อินไลน์" ฟังก์ชัน กล่าวคือ คอมไพเลอร์จะเปลี่ยนโค้ดเพื่อแทนที่ Lambda ด้วยคำสั่งภายใน Lambda
หาก myWith() ในตัวอย่างข้างต้นมีเครื่องหมาย inline
inline myWith(fish.name) {
capitalize()
}จะเปลี่ยนเป็นการเรียกใช้โดยตรงดังนี้
// with myWith() inline, this becomes
fish.name.capitalize()โปรดทราบว่าการแทรกฟังก์ชันขนาดใหญ่จะเพิ่มขนาดโค้ด ดังนั้นจึงควรใช้กับฟังก์ชันง่ายๆ ที่ใช้หลายครั้ง เช่น myWith() ฟังก์ชันของส่วนขยายจากไลบรารีที่คุณได้เรียนรู้ไปก่อนหน้านี้จะมีการทำเครื่องหมาย inline เพื่อให้คุณไม่ต้องกังวลว่าจะมีการสร้างออบเจ็กต์เพิ่มเติม
Single Abstract Method หมายถึงอินเทอร์เฟซที่มีเมธอดเดียว ซึ่งพบบ่อยมากเมื่อใช้ API ที่เขียนด้วยภาษาโปรแกรม Java จึงมีตัวย่อสำหรับคำนี้คือ SAM ตัวอย่างเช่น Runnable ซึ่งมีเมธอดนามธรรมเดียวคือ run() และ Callable ซึ่งมีเมธอดนามธรรมเดียวคือ call()
ใน Kotlin คุณต้องเรียกใช้ฟังก์ชันที่ใช้ SAM เป็นพารามิเตอร์อยู่เสมอ ลองดูตัวอย่างด้านล่าง
- สร้างคลาส Java
JavaRunภายใน example แล้ววางข้อมูลต่อไปนี้ลงในไฟล์
package example;
public class JavaRun {
public static void runNow(Runnable runnable) {
runnable.run();
}
}Kotlin ช่วยให้คุณสร้างออบเจ็กต์ที่ใช้การเชื่อมต่อได้โดยนำหน้าประเภทด้วย object: ซึ่งมีประโยชน์ในการส่งพารามิเตอร์ไปยัง SAM
- กลับไปที่
Fish.ktสร้างฟังก์ชันrunExample()ซึ่งสร้างRunnableโดยใช้object:ออบเจ็กต์ควรใช้run()โดยพิมพ์"I'm a Runnable"
fun runExample() {
val runnable = object: Runnable {
override fun run() {
println("I'm a Runnable")
}
}
}- เรียกใช้
JavaRun.runNow()ด้วยออบเจ็กต์ที่คุณสร้าง
fun runExample() {
val runnable = object: Runnable {
override fun run() {
println("I'm a Runnable")
}
}
JavaRun.runNow(runnable)
}- โทรหา
runExample()จากmain()แล้วเรียกใช้โปรแกรม
⇒ I'm a Runnable
การพิมพ์ต้องใช้ความพยายามอย่างมาก แต่ก็เป็นตัวอย่างที่ดีของวิธีการทำงานของ SAM แน่นอนว่า Kotlin มีวิธีที่ง่ายกว่าในการทำเช่นนี้ นั่นคือใช้ Lambda แทนออบเจ็กต์เพื่อให้โค้ดนี้กระชับขึ้นมาก
- นำโค้ดที่มีอยู่ออกใน
runExampleเปลี่ยนให้เรียกใช้runNow()ด้วย Lambda แล้วเรียกใช้โปรแกรม
fun runExample() {
JavaRun.runNow({
println("Passing a lambda as a Runnable")
})
}
⇒ Passing a lambda as a Runnable
- คุณสามารถทำให้โค้ดนี้กระชับยิ่งขึ้นได้โดยใช้ไวยากรณ์การเรียกพารามิเตอร์สุดท้าย และไม่ต้องใส่วงเล็บ
fun runExample() {
JavaRun.runNow {
println("Last parameter is a lambda as a Runnable")
}
}⇒ Last parameter is a lambda as a Runnable
นั่นคือพื้นฐานของ SAM หรือ Single Abstract Method คุณสามารถสร้างอินสแตนซ์ ลบล้าง และเรียกใช้ SAM ด้วยโค้ดเพียงบรรทัดเดียวโดยใช้รูปแบบ Class.singleAbstractMethod { lambda_of_override }
บทเรียนนี้ได้ทบทวน Lambda และเจาะลึกฟังก์ชันลำดับสูง ซึ่งเป็นส่วนสำคัญของ Kotlin นอกจากนี้ คุณยังได้เรียนรู้เกี่ยวกับคำอธิบายประกอบและช่วงพักที่มีป้ายกำกับ
- ใช้คำอธิบายประกอบเพื่อระบุสิ่งต่างๆ ให้คอมไพเลอร์ เช่น
@file:JvmName("Foo") - ใช้การหยุดที่มีป้ายกำกับเพื่อให้โค้ดออกจากลูปที่ซ้อนกัน เช่น
if (i > 10) break@outerLoop // breaks to outerLoop label - Lambda จะมีประสิทธิภาพมากเมื่อใช้ร่วมกับฟังก์ชันลำดับที่สูงกว่า
- Lambda คือออบเจ็กต์ หากไม่ต้องการสร้างออบเจ็กต์ ให้ทำเครื่องหมายฟังก์ชันด้วย
inlineแล้วคอมไพเลอร์จะใส่เนื้อหาของ Lambda ลงในโค้ดโดยตรง - โปรดใช้
inlineอย่างระมัดระวัง แต่จะช่วยลดการใช้ทรัพยากรของโปรแกรมได้ - SAM (Single Abstract Method) เป็นรูปแบบที่ใช้กันทั่วไป และแลมบ์ดาช่วยให้ใช้งานได้ง่ายขึ้น รูปแบบพื้นฐานคือ
Class.singleAbstractMethod { lamba_of_override } - คลังมาตรฐานของ Kotlin มีฟังก์ชันที่มีประโยชน์มากมาย รวมถึง SAM หลายรายการด้วย ดังนั้นโปรดทำความรู้จักกับสิ่งที่อยู่ในคลังนี้
Kotlin มีอะไรอีกมากมายนอกเหนือจากที่กล่าวถึงในหลักสูตร แต่ตอนนี้คุณก็มีพื้นฐานที่จะเริ่มพัฒนาโปรแกรม Kotlin ของคุณเองแล้ว เราหวังว่าคุณจะตื่นเต้นกับภาษาที่สื่อความหมายนี้ และตั้งตารอที่จะสร้างฟังก์ชันการทำงานเพิ่มเติมในขณะที่เขียนโค้ดน้อยลง (โดยเฉพาะอย่างยิ่งหากคุณมาจากภาษาโปรแกรม Java) การฝึกฝนและเรียนรู้ไปพร้อมๆ กันเป็นวิธีที่ดีที่สุดในการเป็นผู้เชี่ยวชาญด้าน Kotlin ดังนั้นโปรดสำรวจและเรียนรู้เกี่ยวกับ Kotlin ด้วยตนเองต่อไป
เอกสารประกอบ Kotlin
หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อใดก็ตามในหลักสูตรนี้ หรือหากคุณติดขัด https://kotlinlang.org คือจุดเริ่มต้นที่ดีที่สุด
บทแนะนำ Kotlin
เว็บไซต์ https://try.kotlinlang.org มีบทแนะนำที่สมบูรณ์ซึ่งเรียกว่า Kotlin Koans, ตัวแปลภาษาบนเว็บ และชุดเอกสารอ้างอิงที่สมบูรณ์พร้อมตัวอย่าง
หลักสูตร Udacity
หากต้องการดูหลักสูตร Udacity ในหัวข้อนี้ โปรดดูค่ายฝึก Kotlin สำหรับโปรแกรมเมอร์
IntelliJ IDEA
เอกสารประกอบสำหรับ IntelliJ IDEA อยู่ในเว็บไซต์ของ JetBrains
ไลบรารีมาตรฐานของ Kotlin
ไลบรารีมาตรฐานของ Kotlin มีฟังก์ชันที่มีประโยชน์มากมาย ก่อนที่จะเขียนฟังก์ชันหรืออินเทอร์เฟซของคุณเอง ให้ตรวจสอบไลบรารีมาตรฐานเสมอเพื่อดูว่ามีใครช่วยคุณประหยัดเวลาไปได้บ้างหรือไม่ โปรดกลับมาตรวจสอบเป็นครั้งคราว เนื่องจากเราเพิ่มฟังก์ชันใหม่ๆ อยู่เสมอ
บทแนะนำ Kotlin
เว็บไซต์ https://try.kotlinlang.org มีบทแนะนำที่สมบูรณ์ซึ่งเรียกว่า Kotlin Koans, ตัวแปลภาษาบนเว็บ และชุดเอกสารอ้างอิงที่สมบูรณ์พร้อมตัวอย่าง
หลักสูตร Udacity
หากต้องการดูหลักสูตร Udacity ในหัวข้อนี้ โปรดดูค่ายฝึก Kotlin สำหรับโปรแกรมเมอร์
IntelliJ IDEA
เอกสารประกอบสำหรับ IntelliJ IDEA อยู่ในเว็บไซต์ของ JetBrains
ส่วนนี้แสดงรายการการบ้านที่เป็นไปได้สำหรับนักเรียน/นักศึกษาที่กำลังทำ Codelab นี้เป็นส่วนหนึ่งของหลักสูตรที่สอนโดยผู้สอน ผู้สอนมีหน้าที่ดำเนินการต่อไปนี้
- มอบหมายการบ้านหากจำเป็น
- สื่อสารกับนักเรียนเกี่ยวกับวิธีส่งงานที่ได้รับมอบหมาย
- ให้คะแนนงานการบ้าน
ผู้สอนสามารถใช้คำแนะนำเหล่านี้ได้มากน้อยตามที่ต้องการ และควรมีอิสระในการมอบหมายการบ้านอื่นๆ ที่เห็นว่าเหมาะสม
หากคุณกำลังทำ Codelab นี้ด้วยตนเอง โปรดใช้แบบฝึกหัดเหล่านี้เพื่อทดสอบความรู้ของคุณ
ตอบคำถามต่อไปนี้
คำถามที่ 1
ใน Kotlin คำว่า SAM ย่อมาจาก
▢ การจับคู่อาร์กิวเมนต์ที่ปลอดภัย
▢ วิธีการเข้าถึงแบบง่าย
▢ Single Abstract Method
▢ วิธีการเข้าถึงเชิงกลยุทธ์
คำถามที่ 2
ข้อใดต่อไปนี้ไม่ใช่ฟังก์ชันส่วนขยายของ Kotlin Standard Library
▢ elvis()
▢ apply()
▢ run()
▢ with()
คำถามที่ 3
ข้อใดต่อไปนี้ไม่เป็นจริงเกี่ยวกับ Lambda ใน Kotlin
▢ แลมบ์ดาคือฟังก์ชันที่ไม่ระบุชื่อ
▢ แลมบ์ดาคือออบเจ็กต์ เว้นแต่จะมีการแทรกในบรรทัด
▢ Lambda ใช้ทรัพยากรมากและไม่ควรใช้
▢ ส่ง Lambda ไปยังฟังก์ชันอื่นๆ ได้
คำถามที่ 4
ป้ายกำกับใน Kotlin จะระบุด้วยตัวระบุตามด้วย
▢ :
▢ ::
▢ @:
▢ @
ยินดีด้วย คุณทำ Codelab หลักสูตรติวเข้ม Kotlin สำหรับโปรแกรมเมอร์เสร็จสมบูรณ์แล้ว
ดูภาพรวมของหลักสูตร รวมถึงลิงก์ไปยังโค้ดแล็บอื่นๆ ได้ที่ "Kotlin Bootcamp for Programmers: Welcome to the course"