最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kotlin - Type inference of heterogeneous collections - Stack Overflow

programmeradmin1浏览0评论

Can someone please explain why res2 in the REPL session shown below is inferred as List<Any>? I thought since both Int and Char are Serializable (evidenced by res0 and res1), then res2 should also be list<Serializable>. What is different about res2?

[0] listOf('A', Pair('X', 'Y'))
res0: List<java.io.Serializable> = [A, (X, Y)]
[1] listOf(1, Pair('X', 'Y'))
res1: List<java.io.Serializable> = [1, (X, Y)]
[2] listOf(1, 'A')
res2: List<Any> = [1, A] 

Can someone please explain why res2 in the REPL session shown below is inferred as List<Any>? I thought since both Int and Char are Serializable (evidenced by res0 and res1), then res2 should also be list<Serializable>. What is different about res2?

[0] listOf('A', Pair('X', 'Y'))
res0: List<java.io.Serializable> = [A, (X, Y)]
[1] listOf(1, Pair('X', 'Y'))
res1: List<java.io.Serializable> = [1, (X, Y)]
[2] listOf(1, 'A')
res2: List<Any> = [1, A] 
Share Improve this question asked Mar 11 at 13:04 k314159k314159 11.4k1 gold badge25 silver badges65 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 3

The type of listOf(1, 'A') should be a List of an intersection type between Comparable<*> and Serializable. After all, Int and Char are also Comparable.

fun main() {
    val x = listOf(1, 'A')
    // both of these compile
    f(x)
    g(x)
}

fun f(x: List<Serializable>) {}
fun g(x: List<Comparable<*>>) {}

It is important that the x above is declared in a statement scope (See scopes), in the body of main. If it had been declared in a declaration scope (such as the top level),

val x = listOf(1, 'A') // this is now in a declaration scope
fun main() {
    // now none of these compile!
    f(x)
    g(x)
}

fun f(x: List<Serializable>) {}
fun g(x: List<Comparable<*>>) {}

This is because the type of a non-local property like x cannot contain non-denotable types (e.g. intersection types), and so type approximation is applied. Type approximation replaces the intersection type with the GLB of Serializable and Comparable<*> , which is Any.

Something similar is happening in the REPL. You can think of the expressions you enter into the REPL as being assigned to global properties called res0, res1, etc. The type that the REPL produces as output is kind of like printing ::res0.returnType. There is no KType that can represent a intersection type, so the intersection type must be approximated.


Even if you write val x = listOf(1, 'A'), the type of x will still be List<Any>, because the REPL treats this declaration similar to a top-level declaration like in the code snippet above. This can be shown by the fact that smart casts are not possible on top level vars:

>>> var x: Int? = null
>>> if (x != null) { println(x.toLong()) }
error: smart cast to 'Int' is impossible, because 'x' is a mutable property that could have been changed by this time
if (x != null) { println(x.toLong()) }
发布评论

评论列表(0)

  1. 暂无评论