尝试返回已检查通用参数的值时,为什么会出现类型不匹配?

时间:2016-10-31 21:45:35

标签: kotlin

在以下代码"Happy Halloween!"中,42等标记为"类型不匹配。" (必需:T,Found:String(或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()
}

4 个答案:

答案 0 :(得分:1)

你可以这样写:

display: inline-block

运行以下内容:

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)))
}

在此处详细了解内联函数和已知参数:Reified type parameters

答案 1 :(得分:0)

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

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.那么你的代码就可以了。

答案 2 :(得分:0)

如果我简化你的例子:

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>或Jackson TypeReference<T>这样的内容 文档引用此博客文章解释了这个想法:http://gafter.blogspot.ca/2006/12/super-type-tokens.html

答案 3 :(得分:0)

>>> a = np.random.randint(1, 10, size=(1000,)) >>> %timeit concatenated_ranges(a) 10000 loops, best of 3: 142 us per loop >>> %timeit concatenated_ranges2(a) 10000 loops, best of 3: 72.6 us per loop 运算符与Java的is运算符非常相似,在运行时执行。

因此,在编译时,编译器不知道实际类型,因此会出现编译错误。

这是另一个简单的例子:

instanceof