0Pricing
Kotlin Academy · บทเรียน

การลบชนิดและพารามิเตอร์ชนิด reified

ใช้ reified ร่วมกับฟังก์ชัน inline เพื่อเข้าถึงข้อมูลชนิดขณะรันไทม์

การลบชนิดและพารามิเตอร์ชนิด reified เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

การลบชนิดข้อมูลคืออะไร

ขณะรันไทม์ JVM จะลบอาร์กิวเมนต์ชนิดข้อมูลเจเนอริกออก List<String> และ List<Int> จึงเป็นเพียง List ทั้งคู่ ซึ่งจำกัดการดำเนินการด้านชนิดข้อมูลขณะรันไทม์สำหรับเจเนอริก

fun main() {
    val strings: List<String> = listOf("a", "b")
    val ints: List<Int> = listOf(1, 2)
    println(strings.javaClass == ints.javaClass) // true: both ArrayList
    println(strings is List<*>)  // OK with star
    // println(strings is List<String>) // warning: unchecked cast
}

ปัญหา: ไม่สามารถตรวจสอบชนิดข้อมูลที่ถูกลบได้

คุณไม่สามารถใช้ is กับอาร์กิวเมนต์ชนิดข้อมูลเจเนอริกที่ระบุเฉพาะได้ เพราะข้อมูลชนิดข้อมูลหายไปแล้วขณะรันไทม์

fun checkType(obj: Any) {
    // This works:
    if (obj is List<*>) println("It's a list of something")
    // This doesn't compile cleanly:
    // if (obj is List<String>) println("It's a list of strings") // unchecked
}
fun main() {
    checkType(listOf("hello"))
    checkType(42)
}

สรุปฟังก์ชัน inline

inline จะคัดลอกตัวฟังก์ชันไปยังจุดเรียกใช้ขณะคอมไพล์ สิ่งนี้ทำให้ใช้ reified ได้ โดยอาร์กิวเมนต์ชนิดข้อมูลจะถูกแทนที่ที่จุดเรียกใช้ด้วย

inline fun <T> myRun(block: () -> T): T = block()
fun main() {
    val result = myRun { 42 }
    println(result) // 42
    // The compiler inlines the lambda body — no object allocation
}

reified: การเข้าถึง T ขณะรันไทม์

การใช้ inline ร่วมกับ reified จะรักษาอาร์กิวเมนต์ชนิดข้อมูลไว้ที่จุดเรียกใช้ ทำให้ใช้ is, as และ ::class กับ T ได้

inline fun <reified T> isInstance(value: Any): Boolean = value is T
fun main() {
    println(isInstance<String>("hello"))  // true
    println(isInstance<Int>("hello"))     // false
    println(isInstance<List<*>>(listOf())) // true
}

การหาค่า KClass ของ T

เมื่อใช้ reified T คุณสามารถหาค่า T::class ขณะรันไทม์ได้ ซึ่งโดยปกติจะทำไม่ได้ในฟังก์ชันเจเนอริก

inline fun <reified T> classNameOf(): String = T::class.simpleName ?: "Unknown"
fun main() {
    println(classNameOf<String>())   // String
    println(classNameOf<Int>())      // Int
    println(classNameOf<List<*>>())  // List
}

การแปลงชนิดอย่างปลอดภัยด้วย reified

ใช้ reified เพื่อเขียนฟังก์ชันช่วยสำหรับแปลงชนิดข้อมูลอย่างปลอดภัย ซึ่งจะคืนค่า null แทนการส่งข้อผิดพลาด

inline fun <reified T> Any?.safeCast(): T? = this as? T
fun main() {
    val obj: Any = "Hello"
    val s: String? = obj.safeCast<String>()
    val i: Int? = obj.safeCast<Int>()
    println(s) // Hello
    println(i) // null
}

การแยกวิเคราะห์ JSON ด้วย reified

ไลบรารีอย่าง Gson หรือ kotlinx.serialization ใช้ reified เพื่ออนุมานชนิดข้อมูลเป้าหมายที่จุดเรียกใช้ โดยไม่ต้องส่งออบเจ็กต์ Class อย่างชัดเจน

import com.google.gson.Gson
// Simulated without real Gson:
inline fun <reified T> parseJson(json: String): T {
    return Gson().fromJson(json, T::class.java)
}
// Usage:
// val user: User = parseJson<User>("""{"name":"Alice"}""")

reified กับ filterIsInstance

filterIsInstance<T>() ของไลบรารีมาตรฐานใช้ reified เพื่อกรองรายการให้เหลือชนิดข้อมูลเฉพาะ โดยไม่ต้องแปลงชนิดด้วยตนเอง

fun main() {
    val mixed: List<Any> = listOf(1, "hello", 2.5, "world", true)
    val strings = mixed.filterIsInstance<String>()
    val ints = mixed.filterIsInstance<Int>()
    println(strings) // [hello, world]
    println(ints)    // [1]
}

ไม่สามารถใช้ reified ในฟังก์ชันที่ไม่ใช่ inline

reified ใช้ได้เฉพาะกับฟังก์ชัน inline เท่านั้น การพยายามใช้โดยไม่มี inline จะทำให้เกิดข้อผิดพลาดขณะคอมไพล์

// Error:
// fun <reified T> broken(): String = T::class.simpleName ?: "?"

// Must be inline:
inline fun <reified T> correct(): String = T::class.simpleName ?: "?"
fun main() {
    println(correct<Double>()) // Double
}

reified กับรีเฟลกชัน

ผสาน reified เข้ากับรีเฟลกชันเพื่อตรวจสอบพร็อพเพอร์ตีหรือคำกำกับของชนิดข้อมูลแบบไดนามิก โดยไม่ต้องเขียนพารามิเตอร์ Class ซ้ำซาก

inline fun <reified T : Any> properties(): List<String> =
    T::class.members.map { it.name }
data class Point(val x: Int, val y: Int)
fun main() {
    println(properties<Point>()) // [x, y, component1, component2, copy, equals, hashCode, toString]
}

ภาคปฏิบัติ: ตัวค้นหาบริการที่ปลอดภัยด้านชนิดข้อมูล

ใช้ reified เพื่อสร้างตัวค้นหาบริการที่จับคู่ KClass กับอินสแตนซ์ สำหรับ DI แบบเบาโดยไม่ต้องใช้ตัวประมวลผลคำกำกับ

val registry = mutableMapOf<kotlin.reflect.KClass<*>, Any>()
inline fun <reified T : Any> register(instance: T) { registry[T::class] = instance }
@Suppress("UNCHECKED_CAST")
inline fun <reified T : Any> resolve(): T = registry[T::class] as T
class Logger { fun log(msg: String) = println("[LOG] $msg") }
fun main() {
    register(Logger())
    resolve<Logger>().log("Service located!")
}

ข้อจำกัดของ reified

พารามิเตอร์ชนิดข้อมูลแบบ reified ไม่สามารถใช้ในบริบทที่ไม่ใช่ inline ไม่สามารถจัดเก็บชนิดข้อมูลไว้ใช้ภายหลัง และไม่สามารถส่งต่อให้ฟังก์ชันที่ไม่ใช่ inline ซึ่งต้องใช้ชนิดข้อมูลขณะรันไทม์ได้

inline fun <reified T> foo() {
    val clazz = T::class // OK here
    // bar(clazz)        // must pass clazz explicitly to non-inline funs
    println(clazz.simpleName)
}
fun bar(clazz: kotlin.reflect.KClass<*>) = println(clazz.simpleName)
fun main() { foo<String>() }

ตรวจสอบความเข้าใจ

พารามิเตอร์ชนิดข้อมูลต้องมีเงื่อนไขใดจึงจะเป็น reified ได้

สรุปทบทวน

การลบชนิดข้อมูล จะลบข้อมูลชนิดข้อมูลเจเนอริกออกขณะรันไทม์ ส่วน reified บนฟังก์ชัน inline จะรักษาอาร์กิวเมนต์ชนิดข้อมูลไว้ที่จุดเรียกใช้ ทำให้ใช้ is, as, ::class และรีเฟลกชันกับ T ได้ โดยไม่ต้องส่งออบเจ็กต์ Class ด้วยตนเอง

คำถามที่พบบ่อย

บทเรียน “การลบชนิดและพารามิเตอร์ชนิด reified” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การลบชนิดและพารามิเตอร์ชนิด reified” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การลบชนิดและพารามิเตอร์ชนิด reified”

ใช้ reified ร่วมกับฟังก์ชัน inline เพื่อเข้าถึงข้อมูลชนิดขณะรันไทม์ คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การลบชนิดและพารามิเตอร์ชนิด reified” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม

ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ฟังก์ชัน Generic และข้อจำกัดชนิดด้วย where
  2. ความแปรผัน ณ จุดประกาศ: in และ out
  3. Star Projection และการใช้ *
  4. การลบชนิดและพารามิเตอร์ชนิด reified
← กลับไปที่ Kotlin Academy