Kotlin 中的 reified 关键字是如何工作的? [英] How does the reified keyword in Kotlin work?

查看:30
本文介绍了Kotlin 中的 reified 关键字是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解 reified 关键字的用途,显然是 它允许我们对泛型进行反思.

I'm trying to understand the purpose of the reified keyword, apparently it's allowing us to do reflection on generics.

但是,当我不使用它时,它也能正常工作.有人愿意解释这什么时候会产生实际差异吗?

However, when I leave it out it works just as fine. Anyone care to explain when this makes an actual difference?

推荐答案

TL;DR:reified 有什么用

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

在像 myGenericFun 这样的泛型函数的主体中,您不能访问类型 T 因为它仅在编译时可用但是在运行时擦除.因此,如果您想在函数体中使用泛型类型作为普通类,您需要显式地将类作为参数传递,如myGenericFun所示.

In the body of a generic function like myGenericFun, you can't access the type T because it's only available at compile time but erased at runtime. Therefore, if you want to use the generic type as a normal class in the function body you need to explicitly pass the class as a parameter as shown in myGenericFun.

如果你创建一个带有reified Tinline函数,T的类型甚至可以被访问在运行时,因此您不需要额外传递 Class.您可以像使用普通类一样使用 T - 例如你可能想检查一个变量是否是一个实例 T,你可以很容易地做到:myVar is T.

If you create an inline function with a reified T, the type of T can be accessed even at runtime, and thus you do not need to pass the Class<T> additionally. You can work with T as if it was a normal class - e.g. you might want to check whether a variable is an instance of T, which you can easily do then: myVar is T.

这样一个reified类型Tinline函数如下所示:

Such an inline function with reified type T looks as follows:

inline fun <reified T> myGenericFun()


reified 如何工作

您只能将 reifiedinline 函数结合使用.通过这样做,您指示编译器将函数的字节码复制到调用该函数的每个位置(编译器内联"该函数).当您使用 reified 类型调用 inline 函数时,编译器必须能够知道作为类型参数传递的实际类型,以便它可以修改生成的字节码以使用直接对应的类.因此,像 myVar is T 这样的调用在字节码中变成了 myVar is String(如果类型参数是 String).


How reified works

You can only use reified in combination with an inline function. By doing so, you instruct the compiler to copy the function's bytecode to every spot the function is invoked from (the compiler "inlines" the function). When you call an inline function with reified type, the compiler has to be able to know the actual type passed as a type argument so that it can modify the generated bytecode to use the corresponding class directly. Therefore a call like myVar is T becomes myVar is String in the bytecode (if the type argument is String).

让我们看一个例子,它展示了 reified 是多么有用.我们想为 String 创建一个名为 toKotlinObject 的扩展函数,它尝试将 JSON 字符串转换为普通 Kotlin 对象,其类型由函数的泛型类型 T 指定.我们可以使用 com.fasterxml.jackson.module.kotlin为此,第一种方法如下:

Let's have a look at an example that shows how helpful reified can be. We want to create an extension function for String called toKotlinObject that tries to convert a JSON string to a plain Kotlin object with a type specified by the function's generic type T. We can use com.fasterxml.jackson.module.kotlin for this and the first approach is the following:

a) 第一种没有具体化类型的方法

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

readValue 方法采用一种应该将 JsonObject 解析为的类型.如果我们尝试获取类型参数 TClass,编译器会抱怨:"Cannot use 'T' as reified type parameter.改用类."

The readValue method takes a type that it is supposed to parse the JsonObject to. If we try to get the Class of the type parameter T, the compiler complains: "Cannot use 'T' as reified type parameter. Use a class instead."

b) 使用显式 Class 参数

b) Workaround with explicit Class parameter

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

作为一种解决方法,可以将 TClass 设为方法参数,然后将其用作 readValue 的参数.这是有效的,并且是通用 Java 代码中的常见模式.可以这样调用:

As a workaround, the Class of T can be made a method parameter, which then used as an argument to readValue. This works and is a common pattern in generic Java code. It can be called as follows:

data class MyJsonType(val name: String)

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

c) Kotlin 方式:reified

使用带有 reified 类型参数 Tinline 函数可以实现不同的函数:

Using an inline function with reified type parameter T makes it possible to implement the function differently:

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

TClass 不需要另外取,T 可以像普通类一样使用.对于客户端,代码如下所示:

There’s no need to take the Class of T additionally, T can be used as if it was an ordinary class. For the client the code looks like this:

json.toKotlinObject<MyJsonType>()

重要说明:使用 Java

reified 类型的内联函数不能从 Java 代码中调用.

这篇关于Kotlin 中的 reified 关键字是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆