ฉันพยายามทำความเข้าใจจุดประสงค์ของreified
คำหลักดูเหมือนว่ามันช่วยให้เราสามารถไตร่ตรองเกี่ยวกับยาสามัญได้
อย่างไรก็ตามเมื่อฉันปล่อยมันออกไปมันก็ใช้งานได้ดี ใครสนใจที่จะอธิบายเมื่อสิ่งนี้สร้างความแตกต่างที่แท้จริง?
ฉันพยายามทำความเข้าใจจุดประสงค์ของreified
คำหลักดูเหมือนว่ามันช่วยให้เราสามารถไตร่ตรองเกี่ยวกับยาสามัญได้
อย่างไรก็ตามเมื่อฉันปล่อยมันออกไปมันก็ใช้งานได้ดี ใครสนใจที่จะอธิบายเมื่อสิ่งนี้สร้างความแตกต่างที่แท้จริง?
คำตอบ:
reified
ดีสำหรับfun <T> myGenericFun(c: Class<T>)
ในเนื้อความของฟังก์ชันทั่วไปเช่นmyGenericFun
คุณไม่สามารถเข้าถึงประเภทได้T
เนื่องจากมีให้ใช้งานในเวลาคอมไพล์เท่านั้น แต่จะถูกลบเมื่อรันไทม์ ดังนั้นหากคุณต้องการใช้ประเภททั่วไปเป็นคลาสปกติในเนื้อหาของฟังก์ชันคุณต้องส่งผ่านคลาสเป็นพารามิเตอร์อย่างชัดเจนดังที่แสดงในmyGenericFun
.
หากคุณสร้างinline
ฟังก์ชันด้วยreified T
ประเภทของT
สามารถเข้าถึงได้แม้ในขณะรันไทม์ดังนั้นคุณไม่จำเป็นต้องส่งผ่านClass<T>
เพิ่มเติม คุณสามารถทำงานกับT
ราวกับว่ามันเป็นระดับปกติ - เช่นคุณอาจต้องการตรวจสอบว่าตัวแปรที่เป็นตัวอย่างของการ ที่คุณสามารถทำแล้ว:T
myVar is T
inline
ฟังก์ชันที่มีreified
ประเภทดังกล่าวมีT
ลักษณะดังนี้:
inline fun <reified T> myGenericFun()
reified
ทำงานคุณสามารถใช้reified
ร่วมกับinline
ฟังก์ชันเท่านั้น คุณสั่งให้คอมไพเลอร์คัดลอก bytecode ของฟังก์ชันไปยังทุกจุดที่เรียกใช้ฟังก์ชันจาก (คอมไพเลอร์ "inlines" ของฟังก์ชัน) เมื่อคุณเรียกใช้inline
ฟังก์ชันด้วยreified
type คอมไพลเลอร์จะต้องสามารถทราบชนิดจริงที่ส่งผ่านเป็นอาร์กิวเมนต์ type เพื่อให้สามารถแก้ไข bytecode ที่สร้างขึ้นเพื่อใช้คลาสที่เกี่ยวข้องได้โดยตรง ดังนั้นการเรียก like myVar is T
จึงกลายเป็นmyVar is String
bytecode (ถ้าอาร์กิวเมนต์ type เป็นString
)
ลองดูตัวอย่างที่แสดงให้เห็นว่ามีประโยชน์reified
อย่างไร เราต้องการที่จะสร้างฟังก์ชั่นส่วนขยายสำหรับString
เรียกtoKotlinObject
ว่าพยายามที่จะแปลงสตริง JSON ไปยังวัตถุที่ Kotlin T
ธรรมดากับประเภทที่ระบุโดยประเภททั่วไปของฟังก์ชัน เราสามารถใช้com.fasterxml.jackson.module.kotlin
สำหรับสิ่งนี้และแนวทางแรกมีดังต่อไปนี้:
ก) แนวทางแรกที่ไม่มีประเภท reified
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
readValue
วิธีการเตะประเภทที่มันควรจะแยกJsonObject
ไป หากเราพยายามรับClass
พารามิเตอร์ type T
คอมไพเลอร์จะบ่นว่า: "ไม่สามารถใช้ 'T' เป็นพารามิเตอร์ reified type ได้โปรดใช้คลาสแทน"
b) วิธีแก้ปัญหาด้วยClass
พารามิเตอร์ที่ชัดเจน
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
เป็นวิธีแก้ปัญหาที่Class
ของสามารถทำพารามิเตอร์วิธีการซึ่งจากนั้นจะนำมาใช้เป็นข้อโต้แย้งไปยังT
readValue
สิ่งนี้ใช้ได้ผลและเป็นรูปแบบทั่วไปในโค้ด Java ทั่วไป สามารถเรียกได้ดังนี้:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) วิธี Kotlin: reified
การใช้inline
ฟังก์ชันที่มีreified
พารามิเตอร์ type T
ทำให้สามารถใช้ฟังก์ชันได้แตกต่างกัน:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
ไม่จำเป็นต้องใช้Class
ของT
เพิ่มเติมT
สามารถใช้งานได้ราวกับว่าเป็นคลาสธรรมดา สำหรับลูกค้ารหัสจะมีลักษณะดังนี้:
json.toKotlinObject<MyJsonType>()
ฟังก์ชันอินไลน์ที่มีreified
ชนิดไม่สามารถเรียกใช้ได้จากโค้ดJava
ง่าย
* reified คือการให้สิทธิ์ในการใช้งานในเวลาคอมไพล์ (เพื่อเข้าถึง T inside de function)
เช่น:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
ใช้เช่น:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(userObject.name)