Star Projection และการใช้ *
ใช้ star projection กับชนิด generic ที่ไม่ทราบแน่ชัดและทำความเข้าใจข้อจำกัด
Star Projection และการใช้ * เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
การฉายแบบดอกจันคืออะไร
การฉายแบบดอกจัน (*) เป็นวิธีของ Kotlin ในการระบุว่าเป็นชนิดข้อมูลเจเนอริกที่ไม่ทราบอาร์กิวเมนต์ชนิดข้อมูล เป็นทางเลือกที่ปลอดภัยเทียบเท่ากับชนิดดิบหรือไวลด์การ์ดไร้ขอบเขตของ Java <?>
fun printList(list: List<*>) {
for (item in list) println(item)
}
fun main() {
printList(listOf(1, 2, 3))
printList(listOf("a", "b"))
printList(listOf(true, 42, "mixed"))
}การอ่านจากชนิดที่ฉายแบบดอกจัน
จาก List<*> คุณสามารถอ่านสมาชิกเป็น Any? ได้ แต่ไม่สามารถเพิ่มสมาชิกได้ เพราะไม่ทราบชนิดข้อมูลจริง
fun process(list: List<*>) {
val first: Any? = list.firstOrNull()
println("First: $first, Size: ${list.size}")
// list.add("x") // compile error: can't write to List<*>
}
fun main() {
process(listOf(10, 20, 30))
}ดอกจันเทียบกับ out Any
List<*> และ List<out Any?> มีความหมายเทียบเท่ากัน การฉายแบบดอกจันเป็นรูปแบบย่อของการฉายแบบมีความแปรผันร่วมที่ใช้ขอบเขตบน
fun sumStars(list: List<*>): Int = list.size
fun sumOut(list: List<out Any?>): Int = list.size
fun main() {
val l = listOf(1, "two", true)
println(sumStars(l)) // 3
println(sumOut(l)) // 3
}ดอกจันในพารามิเตอร์ฟังก์ชัน
ใช้ * ในลายเซ็นฟังก์ชันเมื่อต้องการรับรูปแบบเจเนอริกใด ๆ แต่จะเรียกใช้ได้เฉพาะเมธอดที่ไม่จำเป็นต้องทราบ T
fun containerInfo(map: Map<*, *>): String {
return "keys=${map.keys.size}, values=${map.values.size}"
}
fun main() {
val m = mapOf(1 to "one", 2 to "two")
println(containerInfo(m))
}ดอกจันกับ MutableList
สำหรับ MutableList<*> คุณสามารถอ่านค่าเป็น Any? ได้ แต่ไม่สามารถเขียนได้เลย คอมไพเลอร์จะป้องกันการกระทำดังกล่าว
fun clearFirstElement(list: MutableList<*>) {
if (list.isNotEmpty()) {
list.removeAt(0) // OK: remove by index doesn't need T
// list.add("x") // Error: can't write unknown type
}
}
fun main() {
val m = mutableListOf(1, 2, 3)
clearFirstElement(m)
println(m) // [2, 3]
}คลาสที่มีการฉายแบบดอกจัน
เมื่อตรวจสอบชนิดของคลาสเจเนอริกขณะรันไทม์ ให้ใช้การฉายแบบดอกจัน เพราะอาร์กิวเมนต์ชนิดข้อมูลจะถูกลบออก
fun isListOfSomething(obj: Any): Boolean {
return obj is List<*> // OK with star
// obj is List<String> // Warning: cannot check erased type
}
fun main() {
println(isListOfSomething(listOf(1, 2))) // true
println(isListOfSomething("not a list")) // false
}พารามิเตอร์ดอกจันหลายรายการ
ฟังก์ชันสามารถมีพารามิเตอร์ที่ฉายแบบดอกจันหลายรายการได้ เมื่อต้องทำงานกับคู่หรือแมปที่มีชนิดข้อมูลไม่ทราบแน่ชัด
fun describeMap(map: Map<*, *>) {
map.forEach { (k, v) ->
println("${k?.javaClass?.simpleName} -> ${v?.javaClass?.simpleName}")
}
}
fun main() {
describeMap(mapOf("key" to 42, 1 to true))
}กรณีที่ไม่ควรใช้ดอกจัน
หลีกเลี่ยงการฉายแบบดอกจันเมื่อต้องเขียนลงในคอลเลกชัน หรือเมื่อสามารถใช้พารามิเตอร์ชนิดข้อมูลที่มีขอบเขตแทนได้ เพราะแบบมีขอบเขตให้ข้อมูลมากกว่า
// Bad: loses type information
fun addToStar(list: MutableList<*>, item: Any?) {
// list.add(item) // compile error
}
// Better: use bounded type parameter
fun <T : Any> addTyped(list: MutableList<T>, item: T) {
list.add(item)
}
fun main() {
val l = mutableListOf("a")
addTyped(l, "b")
println(l)
}ดอกจันกับการตรวจสอบชนิดและการแปลงชนิด
ใช้การฉายแบบดอกจันเพื่อตรวจสอบชนิดของคลาสเจเนอริกด้วยการตรวจสอบอินสแตนซ์ จากนั้นจึงแปลงเป็นชนิดข้อมูลเฉพาะเพื่อใช้งานจริง
fun handleResponse(response: Any) {
if (response is List<*>) {
val list = response as List<*>
println("List with ${list.size} elements")
val first = list.firstOrNull()
if (first is String) println("First string: $first")
}
}
fun main() {
handleResponse(listOf("hello", "world"))
handleResponse(42)
}ภาคปฏิบัติ: ตัวกระจายเหตุการณ์แบบเจเนอริก
ตัวกระจายเหตุการณ์ที่รับ Handler<*> ใด ๆ ได้ แต่ยังกระจายเหตุการณ์ที่มีชนิดข้อมูลได้อย่างปลอดภัย
interface Handler<in T> { fun handle(event: T) }
class LogHandler : Handler<Any> {
override fun handle(event: Any) = println("Event: $event")
}
fun dispatch(handler: Handler<*>, event: Any) {
@Suppress("UNCHECKED_CAST")
(handler as Handler<Any>).handle(event)
}
fun main() {
dispatch(LogHandler(), "click")
dispatch(LogHandler(), 42)
}ดอกจันในบริบท reified
การฉายแบบดอกจันพบได้บ่อยเป็นพิเศษในโค้ดรีเฟลกชันและการซีเรียลไลซ์ ซึ่งมีการตรวจสอบชนิดข้อมูลขณะรันไทม์ผ่าน KClass<*>
fun printClassName(klass: kotlin.reflect.KClass<*>) {
println(klass.simpleName)
}
fun main() {
printClassName(String::class) // String
printClassName(List::class) // List
printClassName(Int::class) // Int
}ตรวจสอบความเข้าใจ
เมื่ออ่านค่าจาก List<*> คุณจะได้ชนิดข้อมูลใด
สรุปทบทวน
การฉายแบบดอกจัน (*) ยอมรับรูปแบบเจเนอริกใด ๆ สำหรับการเข้าถึงแบบอ่านอย่างเดียว ใช้สำหรับการตรวจสอบชนิดข้อมูล ฟังก์ชันช่วยแบบเจเนอริก และรีเฟลกชัน หลีกเลี่ยงเมื่อจำเป็นต้องเขียนลงในคอลเลกชัน หรือเมื่อพารามิเตอร์ชนิดข้อมูลที่มีขอบเขตให้ความปลอดภัยด้านชนิดข้อมูลได้ดีกว่า
คำถามที่พบบ่อย
บทเรียน “Star Projection และการใช้ *” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “Star Projection และการใช้ *” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “Star Projection และการใช้ *”
ใช้ star projection กับชนิด generic ที่ไม่ทราบแน่ชัดและทำความเข้าใจข้อจำกัด คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “Star Projection และการใช้ *” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ฟังก์ชัน Generic และข้อจำกัดชนิดด้วย where
- ความแปรผัน ณ จุดประกาศ: in และ out
- Star Projection และการใช้ *
- การลบชนิดและพารามิเตอร์ชนิด reified