【问题标题】:Kotlin werid compile error related to generics and auto type castKotlin werid 与泛型和自动类型转换相关的编译错误
【发布时间】:2017-01-03 11:16:12
【问题描述】:

我认为这段代码 sn-p 应该可以编译:

package bug

import java.lang.reflect.*

data class Descriptor(val clazz: Class<*>, val modifiers: Int, val info: List<String>) {
    constructor(clazz: Class<*>, modifiers: Int, vararg info: List<String>) :
            this(clazz, modifiers, mutableListOf<String>().apply { info.forEach { this@apply.addAll(it) } })
}

private val AnnotatedElement.info: List<String>
    get() = getAnnotation(Info::class.java)?.values?.toList() ?: listOf<String>()

annotation class Info(val values: Array<String>)

/**
 * A simple abstraction of com.google.common.reflect.Invokable of Guava 20.0.
 * https://github.com/google/guava/blob/v20.0/guava/src/com/google/common/reflect/Invokable.java
 */
abstract class Invokable<T, R> : AccessibleObject(), Member, GenericDeclaration

val <T : AccessibleObject> T.descriptor: Descriptor
    get() = when (this) {
        is Invokable<*, *> ->
            Descriptor(declaringClass,
                       modifiers,
                       info,
                       declaringClass.info)
        else -> throw AssertionError()
    }

这是对Google Guava's Invokable 的方便参考。 给出了Invokable 的简要定义。

上面的代码应该可以正常编译,但是编译器会产生 3 条奇怪的消息,这里是日志输出(经过适当的规范化):

e: /path/to/source.kt: (34, 44): 类型推断失败: val Invokable.declaringClass: Class! 不能应用于 接收者:T#2(描述符的类型参数)参数:()

e: /path/to/source.kt: (35, 44): 类型推断失败:val Invokable.modifiers: Int 不能应用于 接收者:T#2(描述符的类型参数)参数:()

e: /path/to/source.kt: (37, 44): 类型推断失败: val Invokable.declaringClass: Class! 不能应用于 接收者:T#2(描述符的类型参数)参数:()

解决方案很简单:将其分配给一个变量并使用该局部变量。没有手动类型转换或其他麻烦的东西,它会编译。但我很感兴趣 如果这是 kotlin 编译器的错误 或者 我缺少一些关于 kotlin 泛型的信息

编辑:工作代码:

package solution

import java.lang.reflect.*

data class Descriptor(val clazz: Class<*>, val modifiers: Int, val info: List<String>) {
    constructor(clazz: Class<*>, modifiers: Int, vararg info: List<String>) :
            this(clazz, modifiers, mutableListOf<String>().apply { info.forEach { this@apply.addAll(it) } })
}

private val AnnotatedElement.info: List<String>
    get() = getAnnotation(Info::class.java)?.values?.toList() ?: listOf<String>()

annotation class Info(val values: Array<String>)

/**
 * A simple abstraction of com.google.common.reflect.Invokable of Guava 20.0.
 * https://github.com/google/guava/blob/v20.0/guava/src/com/google/common/reflect/Invokable.java
 */
abstract class Invokable<T, R> : AccessibleObject(), Member, GenericDeclaration

val <T : AccessibleObject> T.descriptor: Descriptor
    get() = when (this) {
        is Invokable<*, *> -> {
            val o = this // <---------------------------------CHANGES BEGIN FROM THIS LINE
            Descriptor(o.declaringClass,
                       o.modifiers,
                       info,
                       o.declaringClass.info)
        }
        else -> throw AssertionError()
    }

这是submitted to JetBrains,但他们还没有回复,所以我会一直保持开放,直到他们核实或有人来骂我的愚蠢。

【问题讨论】:

  • 什么是foo?请出示其声明
  • @voddan 嗯,实际上是描述符。抱歉弄错了。
  • 我在任何地方都看不到val Invokable.declaringClass。你也可以提供那个代码吗?
  • @voddan google guava 类,上面已经提供了在线参考。
  • 哦,我以为这是你在Invokable 上的扩展属性。谢谢!

标签: generics kotlin


【解决方案1】:

看来 smart cast 不够聪明。但是您可以使用以下方式给它一个提示:

val <T : AccessibleObject> T.descriptor: Descriptor
get() = when (this) {
    is Invokable<*, *> -> {
        Descriptor(this.declaringClass,
                this.modifiers,
                info,
                this.declaringClass.info)
    }
    else -> throw AssertionError()
}

不需要使用 val 的东西。你只需要给它“一些东西”就可以了。当 IDE 上没有“突出显示”的内容时,它可能会很混乱 :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多