Kotlin'deki reified anahtar kelime nasıl çalışır?


145

reifiedAnahtar kelimenin amacını anlamaya çalışıyorum , görünüşe göre jenerikler üzerinde düşünmemize izin veriyor .

Ancak, onu dışarıda bıraktığımda da gayet iyi çalışıyor. Bunun gerçek bir fark yarattığını açıklamak isteyen var mı?


Yansımanın ne olduğunu bildiğinizden emin misiniz? Ayrıca, tür silme hakkında bir şey duydunuz mu?
MiBAC

3
Genel tür parametreleri çalışma zamanında silinir, henüz yapmadıysanız tür silme hakkında bilgi edinin. Satır içi işlevlerdeki yeniden biçimlendirilmiş tür parametreleri yalnızca yöntem gövdesini satır içi değil, aynı zamanda T :: class.java (normal jenerik türlerle yapamazsınız) gibi şeyler yapmanıza izin veren genel tür parametresi . Yorum olarak koyuyorum çünkü şu anda tam bir cevap verecek vaktim yok ..
F. George

Bir fonksiyonun somut jenerik türüne, yansımaya güvenmeden ve türü argüman olarak iletmek zorunda kalmadan erişim sağlar.
BladeCoder

Yanıtlar:


368

TL; DR: Ne için reifiediyi

fun <T> myGenericFun(c: Class<T>) 

Gibi genel bir işlevin gövdesinde, türe myGenericFunerişemezsiniz Tçünkü yalnızca derleme zamanında kullanılabilir ancak çalışma zamanında silinir . Bu nedenle, genel türü işlev gövdesinde normal bir sınıf olarak kullanmak istiyorsanız, sınıfı içinde gösterildiği gibi bir parametre olarak açıkça iletmeniz gerekir myGenericFun.

Yine de somutlaştırılmış bir inlineişlev oluşturursanız , türüne çalışma zamanında bile erişilebilir ve bu nedenle ek olarak geçmeniz gerekmez . Sen çalışabilir bir değişken bir olup olmadığını kontrol etmek isteyebilirsiniz örneğin, normal bir sınıf sanki örneği kolayca ardından yapabilirsiniz: . TTClass<T>T TmyVar is T

Type inlineile böyle bir işlev aşağıdaki gibi görünür:reifiedT

inline fun <reified T> myGenericFun()

Nasıl reifiedçalışır

Yalnızca reifiedbir inlineişlevle birlikte kullanabilirsiniz . Böyle bir işlev, derleyicinin işlevin bayt kodunu işlevin kullanıldığı her yere kopyalamasını sağlar (işlev "satır içi" halindedir). Gerçekleştirilmiş türle bir satır içi işlevi çağırdığınızda, derleyici , tür bağımsız değişkeni olarak kullanılan gerçek türü bilir ve ilgili sınıfı doğrudan kullanmak için üretilen bayt kodunu değiştirir. Gibi nedenle çağıran myVar is Thaline myVar is String(tip argüman olsaydı String) byte ve zamanında.


Misal

Ne kadar yararlı reifiedolabileceğini gösteren bir örneğe bakalım . Bir JSON dizesini, işlevin genel türü tarafından belirtilen bir türe sahip düz bir Kotlin nesnesine dönüştürmeye çalışan Stringçağrılan için bir uzantı işlevi oluşturmak istiyoruz . Bunun için kullanabiliriz ve ilk yaklaşım şudur:toKotlinObjectTcom.fasterxml.jackson.module.kotlin

a) Reified türü olmayan ilk yaklaşım

fun <T> String.toKotlinObject(): T {
      val mapper = jacksonObjectMapper()
                                                        //does not compile!
      return mapper.readValue(this, T::class.java)
}

readValueYöntem ayrıştırmak gerekiyor o bir türü alır JsonObjectbelirleyin. ClassType parametresini almaya çalışırsak T, derleyici şikayet eder: "Reified type parametresi olarak 'T' kullanılamaz. Bunun yerine bir sınıf kullanın."

b) Açık Classparametre ile geçici çözüm

fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, c.java)
}

Geçici bir çözüm olarak, Classof T, daha sonra bir argüman olarak kullanılan bir yöntem parametresi yapılabilir readValue. Bu çalışır ve jenerik Java kodunda yaygın bir kalıptır. Aşağıdaki gibi çağrılabilir:

data class MyJsonType(val name: String)

val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)

c) Kotlin yolu: reified

Type parametresine inlinesahip bir işlev kullanmak , işlevi farklı şekilde uygulamayı mümkün kılar:reifiedT

inline fun <reified T: Any> String.toKotlinObject(): T {
    val mapper = jacksonObjectMapper()
    return mapper.readValue(this, T::class.java)
}

Almaya gerek yok Classve Tayrıca, Tsıradan bir sınıf olsaydı olarak kullanılabilir. Müşteri için kod şuna benzer:

json.toKotlinObject<MyJsonType>()

Önemli Not: Java ile Çalışmak

İle bir satır içine fonksiyon reifiedtürü olan Java dan çağrılabilir değildir kodu.


6
Kapsamlı yanıtınız için teşekkürler! Bu aslında mantıklı. Merak ettiğim bir şey var, eğer fonksiyon yine de satır içi yapılıyorsa neden şeyleştirilmeye ihtiyaç var? Tür silme işlemini bırakır ve yine de işlevi satır içi yapar mı? Bu bana bir tür israf gibi görünüyor, eğer işlevi satır içine alırsanız, kullanılan türü satır içi olarak görebilirsiniz veya burada yanlış bir şey mi görüyorum?
hl3mukkel

6
Geri bildiriminiz için teşekkürler, aslında size cevabı verebilecek bir şeyden bahsetmeyi unutuyorum: Java'dan normal bir satır içi işlev çağrılabilir, ancak somut bir tür parametresi olan biri bunu yapamaz! Sanırım bu, bir satır içi işlevin her tür parametresinin otomatik olarak somutlaştırılmamasının bir nedeni.
s1m0nw1

Ya işlev, somutlaştırılmış ve somutlaştırılmamış parametrelerin bir karışımı ise? Bu, zaten Java'dan çağrılmaya uygun olmamasına neden oluyor, neden tüm tür parametrelerini otomatik olarak yeniden belirtmiyorsunuz? Kotlin'in neden tüm tür parametreleri için açıkça belirtilmiş olması gerekiyor?
Vairavan

1
ya yığındaki üst arayanlar farklı nesneler için json.toKotlinObject <MyJsonType> () değil, json.toKotlinObject <T> () gerekiyorsa?
yedi

1

BASİT

* derleme zamanında kullanım izni vermektir (işlev içinde T'ye erişmek için)

Örneğin:

 inline fun <reified T:Any>  String.convertToObject(): T{

    val gson = Gson()

    return gson.fromJson(this,T::class.java)

}

gibi kullanarak:

val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
  println(user.name)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.