为什么当我尝试返回一个检查的泛型参数的值时出现类型不匹配?

在下面的代码中, "Happy Halloween!"42等被标记为“类型不匹配”。 (必需:T,找到:字符串(或Int)),但不应该编译器能够推断返回值类型检查是正确的类型?

 interface Type<T> class StringType() : Type<String> class IntType1() : Type<Int> class IntType2(val a: Int, val b: Int) : Type<Int> fun <T> something(type: Type<T>): T = when (type) { is StringType -> "Happy Halloween!" is IntType1 -> 42 is IntType2 -> type.a * type.a + type.b * type.b + type.a * type.b else -> throw IllegalArgumentException() } 

当编译器应用类型擦除时,返回类型将被定义。 所以,让我们说,你使用一个字符串…你的方法将是:

 fun something(type: Type<String>): String = when (type) { is StringType -> "Happy Halloween!" is IntType1 -> 42 //Wrong: you must return String! is IntType2 -> type.a * type.a + type.b * type.b + type.a * type.b else -> throw IllegalArgumentException() } 

这个东西是: 你必须在编译时知道你的返回类型 。 如果你不知道这一点,你必须告诉编译器:

 fun <T> something(type: Type<T>): Any = when (type) { is StringType -> "blabla" is IntType1 -> 42 is IntType2 -> type.a * type.a + type.b * type.b + type.a * type.b else -> throw IllegalArgumentException() } 

对不起,这个代码不是你正在跳的,你将在返回方法后进行投射…

但是你可以这样做:

 fun <T> something(type: Type<T>): T = when (type) { is StringType -> type.b //is IntType1 -> 42 remove this! is IntType2 -> type.a * type.a + type.b * type.b + type.a * type.b else -> throw IllegalArgumentException() } 

假设type.a和type.b被参数化为T.那么你的代码将工作得很好。

如果我简化你的例子:

 interface Type<T> fun <T> something(type: Type<T>): T = when (type) { is Type<String> -> "Happy Halloween!" else -> throw IllegalArgumentException() } 

编译器现在抱怨他: cannot check for instance of erased type

所以问题在于,由于类型擦除, Type<String>Type<Int>在运行时没有区别,所以编译器不会允许这样做。

您可以尝试使用像Gson的TypeToken<T>或杰克逊的TypeReference<T>这个文档是指这个博客文章解释这个想法: http : TypeReference<T>

is运算符很像Java的instanceof运算符,在运行时执行。

所以,在编译时 ,编译器不知道实际的类型,因此你会得到一个编译错误。

这是另一个简单的例子:

 fun <T>f(t: T): T { if (t is Int) return 3 // compilation error else return t } 

你可以这样写:

 interface Type<T> class StringType() : Type<String> class IntType1() : Type<Int> class IntType2(val a: Int, val b: Int) : Type<Int> inline fun <reified T> something(type: Type<T>): T { val result = when(type) { is StringType -> "Happy Halloween" is IntType1 -> 42 is IntType2 -> type.a * type.a + type.b * type.b + type.a * type.b else -> throw IllegalArgumentException() } return if (result is T) result else throw Exception() } 

运行以下内容:

 fun main(args: Array<String>) { println(something(StringType())) println(something(IntType1())) println(something(IntType2(2, 3))) } 

会给你这个输出:

 Happy Halloween 42 19 

了解更多关于内联函数和使用参数的信息: 实体类型参数 。