Gram z refleksją i wyszłam z tym problemem. Podczas korzystania związanego odniesienie klasy poprzez składni ::class
, dostaję kowariantna typ KClass:Jaki jest cel posiadania powiązanego odwołania do klasy typu kowariantu?
fun <T> foo(entry: T) {
with(entry::class) {
this // is instance of KClass<out T>
}
}
Jak mogę nauczyć się od docs, to powróci dokładny typ obiektu, w przypadku gdy jest instancją podtypu z T
, stąd modyfikator wariancji. Jednak to uniemożliwia pobieranie właściwości zadeklarowane w klasie T
i coraz ich wartości (co jest, co usiłuję zrobić)
fun <T> foo(entry: T) {
with(entry::class) {
for (prop in memberProperties) {
val v = prop.get(entry) //compile error: I can't consume T
}
}
}
Okazało się, że to rozwiązanie jest przy użyciu javaClass.kotlin
funkcję przedłużacza na odwołania do obiektu, aby uzyskać zamiast typ niezmienna:
fun <T> foo(entry: T) {
with(entry.javaClass.kotlin) {
this // is instance of KClass<T>
}
}
ten sposób uzyskać zarówno dokładny typ w czasie rzeczywistym i możliwość spożywania typ.
Co ciekawe, jeśli mogę użyć supertypem zamiast generycznego, z drugiej metody I nadal uzyskać dostęp do odpowiedniego typu, bez konieczności wariancji:
class Derived: Base()
fun foo(entry: Base) {
with(entry.javaClass.kotlin) {
println(this == Derived::class)
}
}
fun main(args: Array<String>) {
val derived = Derived()
foo(derived) // prints 'true'
}
Jeśli mam to poprawne, ::class
jest równy wywoływaniu java getClass
, który zwraca typ wariantu z symbolem wieloznacznym, natomiast javaClass
jest getClass
z rzutowaniem na określony typ. Nadal nie rozumiem, dlaczego miałbym kiedykolwiek potrzebować kowariantnego KClassa, kiedy ogranicza mnie to tylko do produkcji typu, biorąc pod uwagę, że istnieją inne sposoby dostępu do dokładnej klasy w czasie wykonywania i korzystania z niej swobodnie, i zastanawiam się, czy bardziej bezpośredni ::class
powinien zwrócić typ niezmienniczy według projektu.
Rozumiem, co mówisz. Ale chodzi mi o to, że jeśli używam someBase(). JavaClass.kotlin, Nadal mam prawidłowy podtyp (pochodne) w czasie wykonywania, ale także nie ma wariancji w czasie kompilacji, ponieważ te funkcje rozszerzające używają generycznych. Wydaje mi się, że składnia :: klasy mogłaby zostać ulepszona tak, aby działała jak javaClass.kotlin, co jest idiomatycznie mniej bezpośrednie. Wydaje mi się, że robią to samo, zwracając klasę kotlin, ale ta ostatnia wykonuje lepszą pracę, a jednocześnie jest bardziej gadatliwa. – devrocca
Jest odwrotnie: '.javaClass' została wprowadzona wcześniej, a brak wariancji w niej był uważany za błędny projekt; '.javaClass' nawet został przestarzały [(w wersji 1.1 RC)] (https://blog.jetbrains.com/kotlin/2017/02/kotlin-1-1-release-candidate-is-here/), ale potem w wersji ostatecznej 1.1 usunięcie zostało usunięte. – hotkey
Interesujące rzeczy. Jeśli jednak muszę wywoływać właściwości pobrane przez odbicie, potrzebuję odbiornika, a typ kowariantowy nie pozwoli mi użyć związanego. Jak zrobiłbyś to w hipotetycznej sprawie, że '.javaClass' nie był dostępny? – devrocca